本文目录导读:

我来为您设计一个完整的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加速
- 数据库索引优化
扩展性
- 微服务架构
- 模块化设计
- 统一的接口规范
这个案例涵盖了在线教育系统的核心功能,可以作为学习参考,实际生产环境需要根据具体需求进行调整和完善。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播