本文目录导读:

我来为您设计一个完整的Java在线教育系统案例,包含详细的功能模块和代码实现。
系统架构设计
技术栈
- 后端: Spring Boot 2.x + MyBatis Plus + Spring Security + JWT
- 前端: Vue.js + Element UI
- 数据库: MySQL + Redis
- 文件存储: 阿里云OSS
系统模块划分
online-education/
├── edu-admin # 后台管理模块
├── edu-api # 接口服务模块
├── edu-common # 公共模块
├── edu-gateway # 网关模块
├── edu-service # 业务服务模块
│ ├── course-service # 课程服务
│ ├── user-service # 用户服务
│ └── order-service # 订单服务
└── edu-utils # 工具类模块
核心功能实现
用户模块
用户实体类
@Data
@TableName("edu_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
@JsonIgnore
private String password;
private String nickname;
private String avatar;
private String email;
private String phone;
@TableLogic
private Integer deleted;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
用户服务实现
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Result login(String username, String password) {
// 查询用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
User user = userMapper.selectOne(wrapper);
if (user == null) {
return Result.error("用户不存在");
}
// 验证密码
if (!BCrypt.checkpw(password, user.getPassword())) {
return Result.error("密码错误");
}
// 生成JWT令牌
String token = JwtUtil.generateToken(user.getId(), user.getUsername());
// 存储用户信息到Redis
redisTemplate.opsForValue().set("user:" + user.getId(), user, 24, TimeUnit.HOURS);
Map<String, Object> data = new HashMap<>();
data.put("token", token);
data.put("user", user);
return Result.success(data);
}
@Override
public Result register(UserDTO userDTO) {
// 检查用户名是否存在
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", userDTO.getUsername());
if (userMapper.selectCount(wrapper) > 0) {
return Result.error("用户名已存在");
}
// 创建新用户
User user = new User();
BeanUtils.copyProperties(userDTO, user);
user.setPassword(BCrypt.hashpw(userDTO.getPassword(), BCrypt.gensalt()));
user.setAvatar("default.png");
userMapper.insert(user);
return Result.success("注册成功");
}
}
课程模块
课程实体类
@Data
@TableName("edu_course")
public class Course {
@TableId(type = IdType.AUTO)
private Long id;
private String title;
private String description;
private String coverUrl;
private Long teacherId;
private String teacherName;
private BigDecimal price;
private Integer status; // 0-未发布 1-已发布
private Integer categoryId;
private Integer viewCount;
private Integer buyCount;
@TableLogic
private Integer deleted;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
课程查询服务
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseMapper courseMapper;
@Autowired
private ChapterMapper chapterMapper;
@Override
public PageResult<CourseVO> getCourseList(CourseQuery query) {
Page<Course> page = new Page<>(query.getPageNum(), query.getPageSize());
QueryWrapper<Course> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1);
// 按分类筛选
if (query.getCategoryId() != null) {
wrapper.eq("category_id", query.getCategoryId());
}
// 按关键词搜索
if (StringUtils.hasText(query.getKeyword())) {
wrapper.and(w -> w.like("title", query.getKeyword())
.or().like("description", query.getKeyword()));
}
// 按价格排序
if ("price_asc".equals(query.getSort())) {
wrapper.orderByAsc("price");
} else if ("price_desc".equals(query.getSort())) {
wrapper.orderByDesc("price");
} else {
wrapper.orderByDesc("create_time");
}
IPage<Course> coursePage = courseMapper.selectPage(page, wrapper);
List<CourseVO> records = coursePage.getRecords().stream()
.map(this::convertToVO)
.collect(Collectors.toList());
return new PageResult<>(coursePage.getTotal(), records);
}
@Override
public CourseDetailVO getCourseDetail(Long id) {
Course course = courseMapper.selectById(id);
if (course == null) {
throw new ServiceException("课程不存在");
}
// 增加浏览量
courseMapper.increaseViewCount(id);
// 查询章节信息
List<Chapter> chapters = chapterMapper.selectList(
new QueryWrapper<Chapter>().eq("course_id", id)
.orderByAsc("sort")
);
CourseDetailVO detailVO = new CourseDetailVO();
BeanUtils.copyProperties(course, detailVO);
detailVO.setChapters(chapters);
return detailVO;
}
private CourseVO convertToVO(Course course) {
CourseVO vo = new CourseVO();
BeanUtils.copyProperties(course, vo);
return vo;
}
}
视频处理模块
视频上传服务
@Service
public class VideoService {
@Autowired
private OSSClient ossClient;
@Value("${aliyun.oss.bucket}")
private String bucketName;
@Value("${aliyun.oss.url}")
private String ossUrl;
public Result uploadVideo(MultipartFile file) {
try {
// 生成文件名称
String fileName = UUID.randomUUID().toString() + "-" + file.getOriginalFilename();
// 上传到OSS
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(file.getContentType());
metadata.setContentLength(file.getSize());
ossClient.putObject(bucketName, fileName, file.getInputStream(), metadata);
// 生成访问URL
String url = ossUrl + "/" + fileName;
// 触发视频转码
processVideo(fileName);
return Result.success(url);
} catch (Exception e) {
throw new ServiceException("视频上传失败");
}
}
private void processVideo(String fileName) {
// 使用阿里云视频处理服务进行转码
// 这里简化处理,实际应该调用多媒体转码服务
}
}
秒杀功能
秒杀服务实现
@Service
public class SeckillServiceImpl implements SeckillService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private SeckillMapper seckillMapper;
@Autowired
private RabbitTemplate rabbitTemplate;
private static final String SECKILL_PREFIX = "seckill:";
@Override
@Transactional(rollbackFor = Exception.class)
public Result seckill(SeckillDTO seckillDTO) {
Long userId = seckillDTO.getUserId();
Long courseId = seckillDTO.getCourseId();
// 1. 预减库存
Long stock = redisTemplate.opsForValue()
.decrement(SECKILL_PREFIX + "stock:" + courseId);
if (stock < 0) {
// 恢复到0
redisTemplate.opsForValue()
.increment(SECKILL_PREFIX + "stock:" + courseId);
return Result.error("商品已售罄");
}
// 2. 防止重复购买
Boolean flag = redisTemplate.opsForValue()
.setIfAbsent(SECKILL_PREFIX + "order:" + userId + ":" + courseId, "1");
if (!Boolean.TRUE.equals(flag)) {
// 回补库存
redisTemplate.opsForValue()
.increment(SECKILL_PREFIX + "stock:" + courseId);
return Result.error("请勿重复购买");
}
// 3. 发送消息到消息队列
SeckillMessage message = new SeckillMessage();
message.setUserId(userId);
message.setCourseId(courseId);
rabbitTemplate.convertAndSend("seckill.exchange", "seckill.queue", message);
return Result.success("秒杀成功,请等待发货");
}
@RabbitListener(queues = "seckill.queue")
public void handleSeckillMessage(SeckillMessage message) {
try {
// 创建订单
createOrder(message.getUserId(), message.getCourseId());
// 删除秒杀标记
redisTemplate.delete(SECKILL_PREFIX + "order:"
+ message.getUserId() + ":" + message.getCourseId());
} catch (Exception e) {
// 处理失败,回补库存
redisTemplate.opsForValue()
.increment(SECKILL_PREFIX + "stock:" + message.getCourseId());
log.error("秒杀处理失败", e);
}
}
private void createOrder(Long userId, Long courseId) {
// 创建订单逻辑
}
}
学习笔记功能
笔记服务
@Service
public class NoteServiceImpl implements NoteService {
@Autowired
private NoteMapper noteMapper;
@Override
public Result addNote(NoteDTO noteDTO) {
Note note = new Note();
BeanUtils.copyProperties(noteDTO, note);
note.setCreateTime(new Date());
noteService.save(note);
return Result.success(note);
}
@Override
public Result getNoteList(Long userId, Long courseId) {
QueryWrapper<Note> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId);
if (courseId != null) {
wrapper.eq("course_id", courseId);
}
List<Note> notes = noteMapper.selectList(wrapper);
return Result.success(notes);
}
@Override
public Result updateNote(NoteDTO noteDTO) {
Note note = noteMapper.selectById(noteDTO.getId());
// 检查权限
if (!note.getUserId().equals(noteDTO.getUserId())) {
throw new ServiceException("无权修改他人笔记");
}
note.setContent(noteDTO.getContent());
note.setUpdateTime(new Date());
noteMapper.updateById(note);
return Result.success("更新成功");
}
}
系统配置类
JWT工具类
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(Long userId, String username) {
Date now = new Date();
Date expireDate = new Date(now.getTime() + expiration * 1000);
return Jwts.builder()
.setSubject(username)
.claim("userId", userId)
.setIssuedAt(now)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
public boolean validateToken(String token) {
try {
Claims claims = parseToken(token);
return claims.getExpiration().after(new Date());
} catch (Exception e) {
return false;
}
}
}
统一返回结果
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("操作成功");
result.setData(data);
return result;
}
public static <T> Result<T> success(String message) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage(message);
return result;
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage(message);
return result;
}
}
全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
public Result handleServiceException(ServiceException e) {
return Result.error(e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result handleException(Exception e) {
log.error("系统异常", e);
return Result.error("系统繁忙,请稍后再试");
}
}
数据库设计
-- 用户表
CREATE TABLE `edu_user` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`nickname` VARCHAR(50) DEFAULT NULL,
`avatar` VARCHAR(255) DEFAULT NULL,
`email` VARCHAR(100) DEFAULT NULL,
`phone` VARCHAR(20) DEFAULT NULL,
`deleted` TINYINT DEFAULT '0',
`create_time` DATETIME DEFAULT NULL,
`update_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 课程表
CREATE TABLE `edu_course` (
`id` BIGINT NOT NULL AUTO_INCREMENT, VARCHAR(200) NOT NULL,
`description` TEXT,
`cover_url` VARCHAR(255) DEFAULT NULL,
`teacher_id` BIGINT DEFAULT NULL,
`teacher_name` VARCHAR(50) DEFAULT NULL,
`price` DECIMAL(10,2) DEFAULT '0.00',
`status` TINYINT DEFAULT '0',
`category_id` INT DEFAULT NULL,
`view_count` INT DEFAULT '0',
`buy_count` INT DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 章节表
CREATE TABLE `edu_chapter` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`course_id` BIGINT NOT NULL, VARCHAR(200) NOT NULL,
`sort` INT DEFAULT '0',
`video_url` VARCHAR(255) DEFAULT NULL,
`duration` INT DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 订单表
CREATE TABLE `edu_order` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`order_no` VARCHAR(32) NOT NULL,
`user_id` BIGINT NOT NULL,
`course_id` BIGINT NOT NULL,
`amount` DECIMAL(10,2) NOT NULL,
`status` TINYINT DEFAULT '0',
`create_time` DATETIME DEFAULT NULL,
`pay_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
系统亮点
高并发处理
- 使用Redis缓存热点数据
- 消息队列异步处理订单
- 数据库连接池优化
安全机制
- JWT令牌认证
- 密码加密存储
- SQL注入防护
性能优化
- 页面静态化
- CDN加速
- 数据库索引优化
扩展性
- 微服务架构
- 模块化设计
- 统一的接口规范
这个案例涵盖了在线教育系统的核心功能,可以作为学习参考,实际生产环境需要根据具体需求进行调整和完善。