1. 项目背景与核心价值
家教预约网站作为教育信息化的重要分支,正在改变传统家教服务模式。这个基于Java+SpringBoot的解决方案,本质上是一个连接家长、学生与教师的双边市场平台。从技术角度看,它实现了三个核心价值:
-
服务数字化:将线下家教匹配流程(需求发布-教师筛选-课时安排-支付评价)完整迁移到线上,典型场景包括家长按学科/年级筛选教师、教师查看可接课时段、双方在线沟通确认等。
-
技术实践闭环:项目完整覆盖现代Web开发的典型技术栈:
- 后端:SpringBoot + MyBatis(数据库交互)
- 前端:Thymeleaf/Vue.js(页面渲染)
- 中间件:Redis(会话缓存)、RabbitMQ(异步消息)
- 部署:Docker容器化
-
教学价值:代码结构清晰展示了分层架构(Controller-Service-DAO),包含JWT鉴权、Excel导出、多数据源等企业级开发必备技能点,是Java学习者从理论到实践的理想过渡项目。
提示:系统默认采用MySQL 8.0作为主数据库,但在
application-prod.yml中已预设多环境配置,可快速切换至Oracle或PostgreSQL。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目结构解析
2.1 基础环境要求
开发环境需要以下组件(以Windows为例):
bash复制# JDK版本
java -version # 需显示17.x(与pom.xml中<java.version>17</java.version>一致)
# 数据库初始化
mysql> CREATE DATABASE teacher_booking CHARACTER SET utf8mb4;
mysql> SOURCE /path/to/sql/init_table.sql # 导入项目提供的DDL脚本
# IDE建议
IntelliJ IDEA 2023+ 或 VS Code with Java Extension Pack
2.2 项目目录关键说明
code复制src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── teacherbooking/
│ │ ├── config/ # 配置类(Swagger/Redis等)
│ │ ├── constant/ # 枚举类(订单状态等)
│ │ ├── controller/ # 前后端分离接口
│ │ ├── dao/ # MyBatis映射接口
│ │ ├── entity/ # 数据库实体
│ │ ├── service/ # 业务逻辑层
│ │ └── TeacherBookingApplication.java # 启动类
│ └── resources/
│ ├── static/ # JS/CSS
│ ├── templates/# Thymeleaf页面
│ ├── application.yml # 主配置
│ └── mybatis/ # SQL映射文件
└── test/ # 单元测试
关键依赖项在pom.xml中已锁定版本:
- Spring Boot Starter: 3.1.0
- MyBatis Plus: 3.5.3.1(简化CRUD操作)
- Hutool: 5.8.16(工具类集合)
- Lombok: 1.18.28(代码简化)
3. 核心功能模块实现
3.1 教师信息管理
采用RBAC(基于角色的访问控制)模型,核心代码在TeacherController:
java复制@RestController
@RequestMapping("/teacher")
public class TeacherController {
@Autowired
private TeacherService teacherService;
@PostMapping("/add")
public ResultVO addTeacher(@Valid @RequestBody TeacherDTO dto) {
return teacherService.addTeacher(dto);
}
@GetMapping("/list")
public PageResult<TeacherVO> listTeachers(
@RequestParam(required = false) String subject,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
return teacherService.getTeachersByPage(subject, page, size);
}
}
技术亮点:
- 使用
@Valid进行DTO参数校验(配合javax.validation注解) - 分页查询通过MyBatis Plus的
PageHelper实现 - 敏感字段(如手机号)在VO层通过
@JsonIgnore脱敏
3.2 预约订单流程
订单状态机设计是业务核心:
mermaid复制stateDiagram-v2
[*] --> PENDING : 用户提交
PENDING --> CONFIRMED : 教师确认
CONFIRMED --> COMPLETED : 课程完成
PENDING --> CANCELLED : 用户取消
CONFIRMED --> CANCELLED : 教师取消
对应数据库表设计:
sql复制CREATE TABLE `tb_order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`student_id` bigint NOT NULL,
`teacher_id` bigint NOT NULL,
`status` enum('PENDING','CONFIRMED','COMPLETED','CANCELLED') DEFAULT 'PENDING',
`course_time` datetime NOT NULL COMMENT '预约上课时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_teacher_id` (`teacher_id`),
KEY `idx_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.3 支付与评价联动
支付成功后触发评价入口的代码逻辑:
java复制@Transactional
public ResultVO handlePaymentSuccess(Long orderId) {
Order order = orderMapper.selectById(orderId);
if (order.getStatus() != OrderStatus.PAID) {
throw new BusinessException(ErrorCode.ORDER_STATUS_ERROR);
}
// 更新订单状态
order.setStatus(OrderStatus.COMPLETED);
orderMapper.updateById(order);
// 发送评价提醒消息
Message message = new Message();
message.setUserId(order.getStudentId());
message.setContent("请对课程【"+order.getId()+"】进行评价");
messageMapper.insert(message);
// 异步通知教师
rabbitTemplate.convertAndSend("teacher.notice", order.getTeacherId());
return ResultVO.success();
}
注意:
@Transactional注解确保数据库操作的原子性,RabbitMQ消息需配置重试机制防止消息丢失。
4. 部署与运维要点
4.1 多环境配置策略
application.yml采用Spring Profile机制:
yaml复制spring:
profiles:
active: @activatedProperties@ # Maven过滤替换
---
spring:
profiles: dev
datasource:
url: jdbc:mysql://localhost:3306/teacher_booking
username: dev_user
password: dev123
---
spring:
profiles: prod
datasource:
url: jdbc:mysql://prod-db:3306/teacher_booking?useSSL=true
username: ${DB_USER}
password: ${DB_PASSWORD}
redis:
host: redis-cluster
启动时指定环境:
bash复制java -jar teacher-booking.jar --spring.profiles.active=prod
4.2 Docker容器化部署
Dockerfile示例:
dockerfile复制FROM openjdk:17-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
使用docker-compose.yml编排服务:
yaml复制version: '3'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_USER=admin
- DB_PASSWORD=${DB_PASS}
depends_on:
- redis
- mysql
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: teacher_booking
redis:
image: redis:alpine
5. 典型问题排查指南
5.1 Lombok注解失效
症状:IDE编译时报"cannot find symbol"错误。
解决方案:
- IntelliJ中安装Lombok插件
- 开启注解处理:Settings > Build > Compiler > Annotation Processors
- 在pom.xml确保版本匹配:
xml复制<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
5.2 多数据源配置冲突
当需要接入第二数据源(如统计库)时,正确配置方式:
java复制@Configuration
@MapperScan(basePackages = "com.teacherbooking.stats.dao",
sqlSessionFactoryRef = "statsSqlSessionFactory")
public class StatsDataSourceConfig {
@Bean(name = "statsDataSource")
@ConfigurationProperties(prefix = "spring.datasource.stats")
public DataSource statsDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "statsSqlSessionFactory")
public SqlSessionFactory statsSqlSessionFactory(
@Qualifier("statsDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mybatis/stats/*.xml"));
return bean.getObject();
}
}
5.3 性能优化实践
- N+1查询问题:在
TeacherService中关联查询教师与评价数据时:
java复制// 错误做法:循环中查询
List<TeacherVO> list = teacherMapper.selectAll();
list.forEach(vo -> {
vo.setComments(commentMapper.selectByTeacherId(vo.getId()));
});
// 正确方案:一次性查询
List<TeacherVO> list = teacherMapper.selectWithComments();
- 缓存策略:对热点数据(如教师评分)使用Redis缓存:
java复制@Cacheable(value = "teacher_rating", key = "#teacherId")
public BigDecimal getTeacherRating(Long teacherId) {
return ratingMapper.calculateAvgRating(teacherId);
}
@CacheEvict(value = "teacher_rating", key = "#comment.teacherId")
public void addComment(Comment comment) {
commentMapper.insert(comment);
}
6. 扩展开发建议
6.1 接入第三方服务
以短信通知为例,抽象服务接口:
java复制public interface SmsService {
void sendVerificationCode(String phone);
}
@Primary
@Service
public class AliyunSmsServiceImpl implements SmsService {
@Override
@SneakyThrows
public void sendVerificationCode(String phone) {
// 调用阿里云SDK
}
}
@Profile("mock")
@Service
public class MockSmsServiceImpl implements SmsService {
@Override
public void sendVerificationCode(String phone) {
logger.info("模拟发送验证码到{}", phone);
}
}
6.2 前端分离改造
若需改为Vue前端:
- 后端新增
@CrossOrigin支持跨域 - 接口返回统一改为
ResultVO格式:
java复制@Data
public class ResultVO<T> {
private Integer code;
private String message;
private T data;
public static <T> ResultVO<T> success(T data) {
ResultVO<T> result = new ResultVO<>();
result.setCode(200);
result.setData(data);
return result;
}
}
- 使用Spring Security配置JWT过滤链
6.3 监控与告警
集成Prometheus监控:
- 添加依赖:
xml复制<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
- 配置端点暴露:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: teacher-booking
- 自定义业务指标:
java复制@RestController
public class OrderController {
private final Counter orderCounter;
public OrderController(MeterRegistry registry) {
this.orderCounter = registry.counter("order.create.count");
}
@PostMapping("/order")
public ResultVO createOrder() {
orderCounter.increment();
// ...
}
}
