Files
campus-activity-system/server/docs/答辩.md
2026-01-19 23:15:20 +08:00

26 KiB
Raw Blame History

校园活动组织与报名系统 - 答辩文档

一、整体框架结构

1.1 技术栈

  • 后端框架: Spring Boot 3.1.8
  • 数据库: MySQL 8.0
  • ORM框架: MyBatis-Plus 3.5.5
  • 安全框架: Spring Security + JWT
  • API文档: Knife4j (Swagger)
  • 工具库: Hutool、Lombok
  • 其他: ZXing二维码生成、iTextPDF生成、EasyExcelExcel导出

1.2 项目结构

server/
├── src/main/java/com/campus/activity/
│   ├── CampusActivityApplication.java          # 启动类
│   ├── common/                                 # 通用类
│   │   ├── Result.java                         # 统一响应结果
│   │   ├── PageResult.java                     # 分页结果
│   │   └── ResultCode.java                     # 响应状态码
│   ├── config/                                 # 配置类
│   │   ├── SecurityConfig.java                 # Spring Security配置
│   │   ├── CorsConfig.java                     # 跨域配置
│   │   ├── Knife4jConfig.java                  # API文档配置
│   │   ├── MybatisPlusConfig.java              # MyBatis-Plus配置
│   │   └── MyMetaObjectHandler.java            # 自动填充处理器
│   ├── controller/                             # 控制器层
│   │   ├── AuthController.java                 # 认证模块
│   │   ├── ActivityController.java             # 活动模块
│   │   ├── RegistrationController.java         # 报名模块
│   │   ├── CheckInController.java              # 签到模块
│   │   ├── ReviewController.java               # 评价模块(我负责)
│   │   └── StatisticsController.java           # 统计模块(我负责)
│   ├── dto/                                    # 数据传输对象
│   │   ├── request/                            # 请求DTO
│   │   │   ├── ReviewRequest.java              # 评价请求
│   │   │   └── ...
│   │   └── response/                           # 响应DTO
│   │       └── ...
│   ├── entity/                                 # 实体类
│   │   ├── User.java                           # 用户实体
│   │   ├── Activity.java                       # 活动实体
│   │   ├── Registration.java                   # 报名实体
│   │   ├── CheckIn.java                        # 签到实体
│   │   └── Review.java                         # 评价实体
│   ├── exception/                              # 异常处理
│   │   ├── BusinessException.java              # 业务异常
│   │   └── GlobalExceptionHandler.java         # 全局异常处理器
│   ├── mapper/                                 # 数据访问层
│   │   ├── UserMapper.java
│   │   ├── ActivityMapper.java
│   │   ├── RegistrationMapper.java
│   │   ├── CheckInMapper.java
│   │   └── ReviewMapper.java                   # 评价Mapper我负责
│   ├── security/                               # 安全相关
│   │   ├── JwtTokenProvider.java               # JWT令牌提供者
│   │   ├── JwtAuthenticationFilter.java        # JWT认证过滤器
│   │   └── UserDetailsServiceImpl.java         # 用户详情服务
│   ├── service/                                # 服务层
│   │   ├── AuthService.java
│   │   ├── ActivityService.java
│   │   ├── RegistrationService.java
│   │   ├── CheckInService.java
│   │   ├── ReviewService.java                  # 评价服务接口(我负责)
│   │   └── StatisticsService.java              # 统计服务接口(我负责)
│   ├── service/impl/                           # 服务实现层
│   │   ├── AuthServiceImpl.java
│   │   ├── ActivityServiceImpl.java
│   │   ├── RegistrationServiceImpl.java
│   │   ├── CheckInServiceImpl.java
│   │   ├── ReviewServiceImpl.java              # 评价服务实现(我负责)
│   │   └── StatisticsServiceImpl.java          # 统计服务实现(我负责)
│   ├── util/                                   # 工具类
│   │   ├── QrCodeUtil.java                     # 二维码工具
│   │   ├── PdfUtil.java                        # PDF工具
│   │   └── CsvUtil.java                        # CSV工具我负责
│   └── vo/                                     # 视图对象
│       ├── ReviewVO.java                       # 评价视图对象(我负责)
│       ├── ActivityStatisticsVO.java           # 活动统计视图对象(我负责)
│       └── OverviewStatisticsVO.java           # 总体统计视图对象(我负责)
├── src/main/resources/
│   ├── application.yml                         # 应用配置
│   └── mapper/                                 # MyBatis XML映射文件
│       ├── ReviewMapper.xml                    # 评价Mapper XML我负责
│       └── ...
└── pom.xml                                     # Maven配置

1.3 分层架构

系统采用经典的分层架构:

  1. Controller层: 接收HTTP请求参数校验调用Service层返回响应
  2. Service层: 业务逻辑处理,事务管理
  3. Mapper层: 数据库访问使用MyBatis-Plus简化CRUD操作
  4. Entity层: 数据库实体映射
  5. DTO层: 数据传输对象,用于接口交互
  6. VO层: 视图对象,用于返回给前端的数据封装

二、我负责的模块

2.1 模块5.4:活动评分与评论模块

2.1.1 功能概述

活动结束后,学生可对参加过的活动进行评价。每个学生对同一活动只能评价一次,管理员可查看所有评价。

2.1.2 核心功能

  1. 提交评价

    • 学生对已参加的活动进行评分1-5分
    • 可选填写评论内容最多500字符
    • 每个学生对同一活动只能评价一次
    • 只有签到过的学生才能评价
  2. 获取活动评价列表

    • 分页查询某个活动的所有评价
    • 显示评价者信息、评分、评论内容、评价时间
  3. 获取我的评价列表

    • 学生查看自己的所有评价记录
    • 支持分页查询

2.1.3 实现细节

Controller层 (ReviewController.java):

@RestController
@RequestMapping("/api/v1/reviews")
public class ReviewController {
    
    // 提交评价
    @PostMapping
    public Result<ReviewVO> createReview(@Valid @RequestBody ReviewRequest request)
    
    // 获取活动评价列表
    @GetMapping("/activity/{activityId}")
    public Result<IPage<ReviewVO>> getActivityReviews(...)
    
    // 获取我的评价列表
    @GetMapping("/my")
    public Result<IPage<ReviewVO>> getMyReviews(...)
}

Service层 (ReviewServiceImpl.java):

核心业务逻辑:

  1. 验证活动是否存在
  2. 检查用户是否已评价该活动(通过唯一约束)
  3. 验证用户是否已签到该活动(只有参加过的学生才能评价)
  4. 插入评价记录
  5. 返回评价详情(包含用户信息和活动信息)

数据验证:

@NotNull(message = "活动ID不能为空")
private Long activityId;

@NotNull(message = "评分不能为空")
@Min(value = 1, message = "评分最小为1")
@Max(value = 5, message = "评分最大为5")
private Integer rating;

@Size(max = 500, message = "评论内容不能超过500个字符")
private String content;

数据库设计:

CREATE TABLE `review` (
    `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
    `user_id` BIGINT NOT NULL,
    `activity_id` BIGINT NOT NULL,
    `rating` TINYINT NOT NULL COMMENT '评分1-5',
    `content` TEXT COMMENT '评论内容',
    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY `uk_user_activity` (`user_id`, `activity_id`),
    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
    FOREIGN KEY (`activity_id`) REFERENCES `activity` (`id`)
);

通过唯一索引 uk_user_activity 确保每个学生对同一活动只能评价一次。

MyBatis XML映射 (ReviewMapper.xml):

<!-- 查询活动评价列表(关联用户和活动信息) -->
<select id="selectActivityReviews" resultType="com.campus.activity.vo.ReviewVO">
    SELECT 
        r.id,
        r.user_id,
        u.name AS user_name,
        u.avatar AS user_avatar,
        r.activity_id,
        a.title AS activity_title,
        r.rating,
        r.content,
        r.created_at
    FROM review r
    LEFT JOIN user u ON r.user_id = u.id
    LEFT JOIN activity a ON r.activity_id = a.id
    WHERE r.activity_id = #{activityId}
    ORDER BY r.created_at DESC
</select>

2.1.4 技术亮点

  1. 数据一致性保证: 通过数据库唯一约束和业务双重验证,确保评价的唯一性
  2. 权限控制: 只有签到过的学生才能评价,防止虚假评价
  3. 分页查询: 使用MyBatis-Plus的分页插件提高大数据量查询性能
  4. 关联查询优化: 在Mapper XML中使用LEFT JOIN一次性获取用户和活动信息减少N+1查询问题
  5. 数据验证: 使用Jakarta Validation进行参数校验提高代码健壮性

2.2 模块5.5:数据统计与导出

2.2.1 功能概述

系统具备基本统计能力例如每个活动的报名人数、实际签到人数、平均评分。管理员可导出活动数据CSV格式

2.2.2 核心功能

  1. 获取活动统计数据

    • 报名人数(已报名+已签到)
    • 签到人数
    • 签到率(签到人数/报名人数)
    • 评价人数
    • 平均评分
    • 评分分布1-5星各有多少人
  2. 导出活动数据

    • 支持CSV格式导出
    • 包含活动基本信息、统计数据
    • 支持Excel直接打开使用UTF-8 BOM头
    • 文件名格式: activity_{activityId}_statistics.csv
  3. 获取总体统计

    • 总活动数
    • 总报名数
    • 总签到数
    • 总评价数
    • 全平台平均评分
    • 最近6个月的月度统计活动和报名数量趋势

2.2.3 实现细节

Controller层 (StatisticsController.java):

@RestController
@RequestMapping("/api/v1/statistics")
public class StatisticsController {
    
    // 获取活动统计数据(管理员)
    @GetMapping("/activity/{activityId}")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<ActivityStatisticsVO> getActivityStatistics(@PathVariable Long activityId)
    
    // 导出活动数据(管理员)
    @GetMapping("/activity/{activityId}/export")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<byte[]> exportActivityData(...)
    
    // 获取总体统计(管理员)
    @GetMapping("/overview")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<OverviewStatisticsVO> getOverviewStatistics()
}

Service层 (StatisticsServiceImpl.java):

核心业务逻辑:

  1. 活动统计 (getActivityStatistics):

    • 统计报名人数状态为1或2的报名记录
    • 统计签到人数
    • 计算签到率(保留两位小数)
    • 统计评价人数和平均评分(保留一位小数)
    • 计算评分分布1-5星各有多少人
  2. 数据导出 (exportActivityData):

    • 调用 CsvUtil 生成CSV文件
    • 设置响应头Content-Disposition、Content-Type
    • 返回文件流
  3. 总体统计 (getOverviewStatistics):

    • 统计全平台的活动、报名、签到、评价总数
    • 计算全平台平均评分
    • 计算最近6个月的月度统计数据

CSV导出工具类 (CsvUtil.java):

核心功能:

  1. 生成UTF-8 BOM头让Excel正确识别中文
  2. 写入表头活动ID、活动名称、开始时间、结束时间、活动地点、报名人数上限、报名人数、签到人数、签到率、评价人数、平均评分、1星、2星、3星、4星、5星
  3. 写入数据行(转义特殊字符,处理逗号、引号、换行符)
  4. 支持Excel直接打开
// 写入BOM头让Excel正确识别UTF-8编码
outputStream.write(0xEF);
outputStream.write(0xBB);
outputStream.write(0xBF);

// 写入表头
StringBuilder header = new StringBuilder();
header.append("活动ID,活动名称,开始时间,结束时间,活动地点,报名人数上限,报名人数,签到人数,签到率,评价人数,平均评分,1星,2星,3星,4星,5星");
outputStream.write(header.toString().getBytes(StandardCharsets.UTF_8));

// CSV转义处理
private String escapeCsv(String value) {
    if (value == null) return "";
    if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
        return "\"" + value.replace("\"", "\"\"") + "\"";
    }
    return value;
}

视图对象:

  1. ActivityStatisticsVO: 活动统计数据视图对象

    • 活动ID、活动标题
    • 报名人数、签到人数、签到率
    • 评价人数、平均评分
    • 评分分布Map<Integer, Long>
  2. OverviewStatisticsVO: 总体统计数据视图对象

    • 总活动数、总报名数、总签到数、总评价数
    • 平均评分
    • 月度统计列表MonthlyStats内部类

2.2.4 技术亮点

  1. 权限控制: 使用 @PreAuthorize("hasRole('ADMIN')") 注解,确保只有管理员可以访问统计和导出功能
  2. 性能优化:
    • 使用流式处理Stream计算平均评分和评分分布
    • 一次性查询所有数据,避免多次数据库访问
  3. 数据精度控制:
    • 签到率保留两位小数
    • 平均评分保留一位小数
  4. CSV导出优化:
    • 添加UTF-8 BOM头解决Excel中文乱码问题
    • 实现CSV转义处理正确处理包含逗号、引号、换行符的数据
    • 使用ByteArrayOutputStream提高性能
  5. 月度统计算法:
    • 动态计算最近6个月的起止时间
    • 使用DateTimeFormatter格式化月份
    • 支持跨年统计

三、答辩模拟

3.1 自我介绍

各位老师好我是XXX负责校园活动组织与报名系统的模块5.4活动评分与评论模块和模块5.5(数据统计与导出模块)的开发工作。

3.2 模块5.4:活动评分与评论模块

老师提问: 请介绍一下你负责的评分与评论模块的设计思路。

我的回答:

评分与评论模块的核心功能是让学生对已参加的活动进行评价。我在设计时考虑了以下几点:

  1. 数据一致性: 通过数据库唯一索引 uk_user_activity 确保每个学生对同一活动只能评价一次,防止重复评价。

  2. 权限控制: 只有签到过的学生才能评价,防止虚假评价。在 ReviewServiceImpl.createReview 方法中,我会先查询签到表,验证用户是否已签到该活动。

  3. 数据验证: 使用Jakarta Validation注解对评分和评论内容进行校验评分必须在1-5分之间评论内容不能超过500字符。

  4. 分页查询: 使用MyBatis-Plus的分页插件支持活动评价列表和我的评价列表的分页查询提高大数据量查询性能。

  5. 关联查询优化: 在 ReviewMapper.xml 中使用LEFT JOIN一次性获取用户和活动信息避免N+1查询问题。

老师提问: 如何防止学生评价自己没有参加的活动?

我的回答:

ReviewServiceImpl.createReview 方法中,我会先查询签到表:

CheckIn checkIn = checkInMapper.selectOne(
    new LambdaQueryWrapper<CheckIn>()
        .eq(CheckIn::getUserId, currentUser.getId())
        .eq(CheckIn::getActivityId, request.getActivityId())
);

if (checkIn == null) {
    throw new BusinessException(ResultCode.NOT_PARTICIPATED);
}

如果签到记录不存在,说明用户没有参加该活动,抛出业务异常,返回错误码 NOT_PARTICIPATED(您未参加该活动,无法评价)。

老师提问: 评分分布是如何计算的?

我的回答:

评分分布在统计模块中计算使用Java Stream的 Collectors.groupingBy 方法:

Map<Integer, Long> ratingDistribution = reviews.stream()
    .collect(Collectors.groupingBy(Review::getRating, Collectors.counting()));

for (int i = 1; i <= 5; i++) {
    ratingDistribution.putIfAbsent(i, 0L);
}

首先按评分分组统计然后确保1-5星都有数据没有的设为0最后返回给前端展示。

3.3 模块5.5:数据统计与导出

老师提问: 请介绍一下统计模块的功能和实现方式。

我的回答:

统计模块提供三个核心功能:

  1. 活动统计: 统计单个活动的报名人数、签到人数、签到率、评价人数、平均评分和评分分布。

  2. 数据导出: 支持将活动统计数据导出为CSV格式方便管理员进行数据分析。

  3. 总体统计: 统计全平台的活动、报名、签到、评价总数以及最近6个月的月度趋势。

实现上我使用了MyBatis-Plus的LambdaQueryWrapper进行条件查询使用Java Stream进行数据聚合计算确保查询效率和代码可读性。

老师提问: CSV导出时如何解决Excel中文乱码问题

我的回答:

CsvUtil.exportActivityData 方法中我添加了UTF-8 BOM头

// 写入BOM头让Excel正确识别UTF-8编码
outputStream.write(0xEF);
outputStream.write(0xBB);
outputStream.write(0xBF);

BOMByte Order Mark是UTF-8编码的特殊标记Excel会自动识别BOM头从而正确显示中文字符。

老师提问: 如果数据中包含逗号、引号或换行符,如何处理?

我的回答:

我实现了 escapeCsv 方法进行CSV转义处理

private String escapeCsv(String value) {
    if (value == null) return "";
    // 如果包含逗号、引号或换行符,需要用引号包裹并转义
    if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
        return "\"" + value.replace("\"", "\"\"") + "\"";
    }
    return value;
}

如果数据中包含逗号、引号或换行符就用双引号包裹并将原有的双引号替换为两个双引号CSV标准转义方式

老师提问: 月度统计是如何计算的?

我的回答:

calculateMonthlyStats 方法中我动态计算最近6个月的起止时间

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

for (int i = 5; i >= 0; i--) {
    LocalDateTime monthStart = now.minusMonths(i).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
    LocalDateTime monthEnd = monthStart.plusMonths(1).minusSeconds(1);
    String monthKey = monthStart.format(formatter);
    
    // 统计该月的活动数和报名数
    Long activityCount = activityMapper.selectCount(
        new LambdaQueryWrapper<Activity>()
            .eq(Activity::getDeleted, 0)
            .between(Activity::getCreatedAt, monthStart, monthEnd)
    );
    
    Long registrationCount = registrationMapper.selectCount(
        new LambdaQueryWrapper<Registration>()
            .eq(Registration::getStatus, 1)
            .between(Registration::getCreatedAt, monthStart, monthEnd)
    );
    
    stats.add(OverviewStatisticsVO.MonthlyStats.builder()
        .month(monthKey)
        .activityCount(activityCount)
        .registrationCount(registrationCount)
        .build());
}

使用 minusMonths 方法计算过去6个月使用 withDayOfMonth(1) 获取每月第一天,使用 plusMonths(1).minusSeconds(1) 获取每月最后一秒,然后统计该月创建的活动和报名数量。

3.4 技术难点与解决方案

老师提问: 在开发过程中遇到了哪些技术难点?你是如何解决的?

我的回答:

  1. CSV导出中文乱码问题: 通过添加UTF-8 BOM头解决让Excel正确识别中文字符。

  2. CSV转义问题: 实现了 escapeCsv 方法正确处理包含逗号、引号、换行符的数据符合CSV标准。

  3. 评分分布计算: 使用Java Stream的 groupingBy 方法进行分组统计,确保代码简洁高效。

  4. 月度统计跨年问题: 使用 DateTimeFormatter 格式化月份支持跨年统计如2025-12到2026-01

  5. 数据精度控制: 使用 Math.round 方法保留指定小数位数,确保签到率保留两位小数,平均评分保留一位小数。

3.5 总结

老师提问: 总结一下你在项目中的收获。

我的回答:

通过参与校园活动组织与报名系统的开发,我收获了很多:

  1. 技术能力提升: 熟练掌握了Spring Boot、MyBatis-Plus、Spring Security等框架的使用深入理解了分层架构设计。

  2. 业务理解能力: 通过需求分析和数据库设计,提升了业务理解和抽象能力。

  3. 问题解决能力: 在开发过程中遇到了CSV导出、数据统计等技术难点通过查阅文档和调试成功解决了这些问题。

  4. 团队协作能力: 与团队成员密切配合,共同完成了系统的开发和测试工作。

  5. 文档编写能力: 编写了详细的API文档和答辩文档提升了文档编写能力。

这次项目开发让我对软件工程有了更深入的理解,也为我今后的学习和工作打下了坚实的基础。


四、项目演示

4.1 API文档访问

系统使用Knife4j生成API文档访问地址http://localhost:8080/doc.html

4.2 模块5.4 API接口

  1. 提交评价

    • 接口: POST /api/v1/reviews
    • 权限: 需要认证
    • 请求体:
    {
      "activityId": 1,
      "rating": 5,
      "content": "非常精彩的活动!"
    }
    
  2. 获取活动评价列表

    • 接口: GET /api/v1/reviews/activity/{activityId}
    • 权限: 公开
    • 参数: current, size
  3. 获取我的评价列表

    • 接口: GET /api/v1/reviews/my
    • 权限: 需要认证
    • 参数: current, size

4.3 模块5.5 API接口

  1. 获取活动统计数据

    • 接口: GET /api/v1/statistics/activity/{activityId}
    • 权限: 管理员
  2. 导出活动数据

    • 接口: GET /api/v1/statistics/activity/{activityId}/export
    • 权限: 管理员
    • 参数: format (csv)
  3. 获取总体统计

    • 接口: GET /api/v1/statistics/overview
    • 权限: 管理员

五、数据库表结构

5.1 评价表 (review)

字段名 类型 约束 说明
id BIGINT PK, AUTO_INCREMENT 评价ID
user_id BIGINT FK, NOT NULL 用户ID
activity_id BIGINT FK, NOT NULL 活动ID
rating TINYINT NOT NULL 评分1-5
content TEXT 评论内容
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 评价时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

索引:

  • uk_user_activity (user_id, activity_id) UNIQUE - 确保每个学生对同一活动只能评价一次
  • idx_activity_id (activity_id)

5.2 关联表

  • user: 用户表
  • activity: 活动表
  • registration: 报名表
  • check_in: 签到表

六、核心代码位置

6.1 模块5.4(评价模块)

  • Controller: src/main/java/com/campus/activity/controller/ReviewController.java
  • Service接口: src/main/java/com/campus/activity/service/ReviewService.java
  • Service实现: src/main/java/com/campus/activity/service/impl/ReviewServiceImpl.java
  • Mapper接口: src/main/java/com/campus/activity/mapper/ReviewMapper.java
  • Mapper XML: src/main/resources/mapper/ReviewMapper.xml
  • Entity: src/main/java/com/campus/activity/entity/Review.java
  • VO: src/main/java/com/campus/activity/vo/ReviewVO.java
  • Request DTO: src/main/java/com/campus/activity/dto/request/ReviewRequest.java

6.2 模块5.5(统计模块)

  • Controller: src/main/java/com/campus/activity/controller/StatisticsController.java
  • Service接口: src/main/java/com/campus/activity/service/StatisticsService.java
  • Service实现: src/main/java/com/campus/activity/service/impl/StatisticsServiceImpl.java
  • VO: src/main/java/com/campus/activity/vo/ActivityStatisticsVO.java
  • VO: src/main/java/com/campus/activity/vo/OverviewStatisticsVO.java
  • Util: src/main/java/com/campus/activity/util/CsvUtil.java

七、测试建议

7.1 评价模块测试

  1. 正常评价: 学生对已参加的活动进行评价,验证评价成功
  2. 重复评价: 同一学生对同一活动再次评价,验证返回错误
  3. 未参加评价: 学生对未参加的活动进行评价,验证返回错误
  4. 评分边界测试: 测试评分为1和5的情况
  5. 评论长度测试: 测试评论内容超过500字符的情况
  6. 分页查询: 测试活动评价列表和我的评价列表的分页功能

7.2 统计模块测试

  1. 活动统计: 验证报名人数、签到人数、签到率、平均评分计算正确
  2. 评分分布: 验证1-5星分布统计正确
  3. 数据导出: 验证CSV文件生成正确Excel可以打开
  4. 中文乱码: 验证CSV文件中文显示正常
  5. 总体统计: 验证全平台统计数据正确
  6. 月度统计: 验证最近6个月统计数据正确支持跨年

八、总结

本次答辩文档详细介绍了校园活动组织与报名系统的整体框架结构以及我负责的模块5.4活动评分与评论模块和模块5.5(数据统计与导出模块)的设计与实现。

在开发过程中我深入理解了Spring Boot、MyBatis-Plus、Spring Security等框架的使用掌握了分层架构设计、数据验证、权限控制、CSV导出等技术提升了自己的技术能力和问题解决能力。

通过本次项目开发,我对软件工程有了更深入的理解,也为我今后的学习和工作打下了坚实的基础。

谢谢各位老师!