本文目录导读:

我来为您设计一个完整的Java考试系统案例,包含前端界面、后端逻辑和数据库设计。
系统架构设计
技术栈
- 后端: Java + Spring Boot + MyBatis
- 前端: Vue.js + Element UI
- 数据库: MySQL
- 认证: JWT
系统功能模块
graph TD
A[考试系统] --> B[用户管理]
A --> C[题库管理]
A --> D[考试管理]
A --> E[成绩管理]
B --> B1[学生端]
B --> B2[教师端]
B --> B3[管理员端]
C --> C1[单选题]
C --> C2[多选题]
C --> C3[判断题]
D --> D1[创建考试]
D --> D2[发布考试]
D --> D3[自动阅卷]
数据库设计
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
real_name VARCHAR(50),
role ENUM('ADMIN', 'TEACHER', 'STUDENT'),
email VARCHAR(100),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 题库表
CREATE TABLE question_bank (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
type ENUM('SINGLE', 'MULTIPLE', 'JUDGE'),
content TEXT NOT NULL,
options TEXT COMMENT 'JSON格式选项',
answer VARCHAR(200),
analysis TEXT COMMENT '解析',
difficulty ENUM('EASY', 'MEDIUM', 'HARD'),
teacher_id BIGINT,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 考试表
CREATE TABLE exam (
id BIGINT PRIMARY KEY AUTO_INCREMENT,VARCHAR(100) NOT NULL,
description TEXT,
duration INT COMMENT '考试时长(分钟)',
total_score INT DEFAULT 100,
start_time DATETIME,
end_time DATETIME,
status ENUM('DRAFT', 'PUBLISHED', 'ENDED'),
teacher_id BIGINT,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
关联表
CREATE TABLE exam_question (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
exam_id BIGINT,
question_id BIGINT,
score DECIMAL(5,2),
sort_order INT
);
-- 考试成绩表
CREATE TABLE exam_result (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
exam_id BIGINT,
student_id BIGINT,
score DECIMAL(5,2),
answer_content TEXT COMMENT 'JSON格式答案',
correct_count INT,
wrong_count INT,
submit_time DATETIME,
status ENUM('IN_PROGRESS', 'SUBMITTED', 'GRADED')
);
核心Java代码
实体类
// 实体类定义
@Data
@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
@JsonIgnore
private String password;
private String realName;
@TableField("role")
private UserRole role;
private String email;
private LocalDateTime createTime;
}
@Data
@TableName("question_bank")
public class Question {
@TableId(type = IdType.AUTO)
private Long id;
private QuestionType type; // SINGLE, MULTIPLE, JUDGE
private String content;
private String options; // JSON格式存储选项
private String answer;
private String analysis;
private Difficulty difficulty;
private Long teacherId;
private LocalDateTime createTime;
}
核心服务层
@Service
@Slf4j
public class ExamService {
@Autowired
private ExamMapper examMapper;
@Autowired
private QuestionMapper questionMapper;
@Autowired
private ExamResultMapper resultMapper;
@Transactional
public Exam createExam(ExamDTO examDTO, Long teacherId) {
Exam exam = new Exam();
BeanUtils.copyProperties(examDTO, exam);
exam.setTeacherId(teacherId);
exam.setStatus(ExamStatus.DRAFT);
examMapper.insert(exam);
// 关联题目
List<ExamQuestion> examQuestions = new ArrayList<>();
for (ExamQuestionDTO questionDTO : examDTO.getQuestions()) {
ExamQuestion eq = new ExamQuestion();
eq.setExamId(exam.getId());
eq.setQuestionId(questionDTO.getQuestionId());
eq.setScore(questionDTO.getScore());
examQuestions.add(eq);
}
examQuestionMapper.insertBatch(examQuestions);
return exam;
}
/**
* 自动阅卷功能
*/
@Transactional
public ExamResult autoGrade(Long examId, Long studentId, List<AnswerDTO> answers) {
// 获取考试题目
List<Question> questions = examQuestionMapper.getQuestionsByExamId(examId);
int correctCount = 0;
int wrongCount = 0;
double totalScore = 0;
List<AnswerDetail> answerDetails = new ArrayList<>();
Map<Long, Double> questionScoreMap = examQuestionMapper.getScoresByExamId(examId);
for (AnswerDTO answer : answers) {
Question question = findQuestion(questions, answer.getQuestionId());
AnswerDetail detail = new AnswerDetail();
detail.setQuestionId(answer.getQuestionId());
detail.setStudentAnswer(answer.getAnswer());
detail.setCorrectAnswer(question.getAnswer());
boolean isCorrect = checkAnswer(question, answer.getAnswer());
detail.setCorrect(isCorrect);
if (isCorrect) {
correctCount++;
totalScore += questionScoreMap.get(question.getId());
} else {
wrongCount++;
}
answerDetails.add(detail);
}
// 保存成绩
ExamResult result = new ExamResult();
result.setExamId(examId);
result.setStudentId(studentId);
result.setScore(totalScore);
result.setCorrectCount(correctCount);
result.setWrongCount(wrongCount);
result.setAnswerContent(JSON.toJSONString(answerDetails));
result.setSubmitTime(LocalDateTime.now());
result.setStatus(ResultStatus.GRADED);
resultMapper.insert(result);
return result;
}
/**
* 检查答案是否正确
*/
private boolean checkAnswer(Question question, String studentAnswer) {
switch (question.getType()) {
case SINGLE:
case JUDGE:
// 单选和判断题直接比较
return question.getAnswer().equalsIgnoreCase(studentAnswer);
case MULTIPLE:
// 多选题需要比较所有选项
Set<String> correctSet = new HashSet<>(
Arrays.asList(question.getAnswer().split(",")));
Set<String> studentSet = new HashSet<>(
Arrays.asList(studentAnswer.split(",")));
return correctSet.equals(studentSet);
default:
return false;
}
}
}
Controller层
@RestController
@RequestMapping("/api/exam")
public class ExamController {
@Autowired
private ExamService examService;
@Autowired
private ScoreService scoreService;
/**
* 获取考试列表
*/
@GetMapping("/list")
public Result<List<ExamVO>> getExamList(
@RequestParam(required = false) Integer page,
@RequestParam(required = false) Integer size,
@RequestParam(required = false) String keyword) {
Page<Exam> result = examService.page(new Page<>(page, size),
new LambdaQueryWrapper<Exam>()
.like(StringUtils.isNotBlank(keyword), Exam::getTitle, keyword)
.orderByDesc(Exam::getCreateTime));
return Result.success(convertToVO(result));
}
/**
* 获取考试详情
*/
@GetMapping("/detail/{examId}")
public Result<ExamDetailVO> getExamDetail(@PathVariable Long examId) {
ExamDetailVO vo = examService.getExamDetail(examId);
return Result.success(vo);
}
/**
* 学生交卷
*/
@PostMapping("/submit")
public Result<ExamResult> submitExam(
@RequestBody SubmitExamRequest request,
@RequestAttribute("user") Long studentId) {
ExamResult result = examService.submitExam(
request.getExamId(),
studentId,
request.getAnswers()
);
return Result.success("交卷成功", result);
}
/**
* 获取成绩列表
*/
@GetMapping("/result/{examId}")
public Result<List<ResultVO>> getExamResults(@PathVariable Long examId) {
List<ResultVO> results = scoreService.getExamResults(examId);
return Result.success(results);
}
}
统计分析模块
@Service
public class StatisticsService {
/**
* 生成考试统计报表
*/
public ExamStatistics generateStatistics(Long examId) {
List<ExamResult> results = resultMapper.selectList(
new LambdaQueryWrapper<ExamResult>()
.eq(ExamResult::getExamId, examId)
.eq(ExamResult::getStatus, ResultStatus.GRADED)
);
ExamStatistics stats = new ExamStatistics();
stats.setTotalStudents(results.size());
stats.setMaxScore(results.stream()
.mapToDouble(ExamResult::getScore).max().orElse(0));
stats.setMinScore(results.stream()
.mapToDouble(ExamResult::getScore).min().orElse(0));
stats.setAverageScore(results.stream()
.mapToDouble(ExamResult::getScore).average().orElse(0));
// 分数段统计
Map<String, Integer> scoreDistribution = new LinkedHashMap<>();
scoreDistribution.put("90-100", 0);
scoreDistribution.put("80-89", 0);
scoreDistribution.put("70-79", 0);
scoreDistribution.put("60-69", 0);
scoreDistribution.put("0-59", 0);
results.forEach(result -> {
double score = result.getScore();
if (score >= 90) {
scoreDistribution.put("90-100",
scoreDistribution.get("90-100") + 1);
} else if (score >= 80) {
scoreDistribution.put("80-89",
scoreDistribution.get("80-89") + 1);
} else if (score >= 70) {
scoreDistribution.put("70-79",
scoreDistribution.get("70-79") + 1);
} else if (score >= 60) {
scoreDistribution.put("60-69",
scoreDistribution.get("60-69") + 1);
} else {
scoreDistribution.put("0-59",
scoreDistribution.get("0-59") + 1);
}
});
stats.setScoreDistribution(scoreDistribution);
// 题目正确率分析
Map<Long, Double> questionAccuracy = analyzeQuestionAccuracy(examId);
stats.setQuestionAccuracy(questionAccuracy);
return stats;
}
private Map<Long, Double> analyzeQuestionAccuracy(Long examId) {
List<ExamResult> results = resultMapper.selectList(
new LambdaQueryWrapper<ExamResult>()
.eq(ExamResult::getExamId, examId)
);
Map<Long, Integer> totalCount = new HashMap<>();
Map<Long, Integer> correctCount = new HashMap<>();
for (ExamResult result : results) {
List<AnswerDetail> details = JSON.parseArray(
result.getAnswerContent(), AnswerDetail.class);
for (AnswerDetail detail : details) {
totalCount.merge(detail.getQuestionId(), 1, Integer::sum);
if (detail.isCorrect()) {
correctCount.merge(detail.getQuestionId(), 1, Integer::sum);
}
}
}
Map<Long, Double> accuracyMap = new HashMap<>();
correctCount.forEach((questionId, correct) -> {
int total = totalCount.getOrDefault(questionId, 0);
accuracyMap.put(questionId, total > 0 ?
(double) correct / total * 100 : 0);
});
return accuracyMap;
}
}
前端Vue核心代码
// ExamList.vue - 考试列表组件
<template>
<div class="exam-container">
<el-card v-for="exam in exams" :key="exam.id" class="exam-card">
<div class="exam-header">
<h3>{{ exam.title }}</h3>
<el-tag :type="getStatusType(exam.status)">
{{ getStatusLabel(exam.status) }}
</el-tag>
</div>
<p class="exam-desc">{{ exam.description }}</p>
<div class="exam-info">
<span>考试时长: {{ exam.duration }}分钟</span>
<span>满分: {{ exam.totalScore }}</span>
</div>
<div class="exam-actions">
<el-button
v-if="exam.status === 'PUBLISHED'"
type="primary"
@click="startExam(exam.id)">
开始考试
</el-button>
<el-button @click="viewResult(exam.id)">
查看成绩
</el-button>
</div>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
exams: [],
loading: false
}
},
created() {
this.fetchExams()
},
methods: {
async fetchExams() {
this.loading = true
try {
const res = await this.$http.get('/api/exam/list')
this.exams = res.data
} finally {
this.loading = false
}
},
getStatusType(status) {
const types = {
'DRAFT': 'info',
'PUBLISHED': 'success',
'ENDED': 'warning'
}
return types[status] || 'info'
},
getStatusLabel(status) {
const labels = {
'DRAFT': '草稿',
'PUBLISHED': '进行中',
'ENDED': '已结束'
}
return labels[status] || status
},
startExam(id) {
this.$router.push(`/exam/${id}/start`)
},
viewResult(id) {
this.$router.push(`/exam/${id}/result`)
}
}
}
</script>
// ExamTaking.vue - 考试答题组件
<template>
<div class="exam-taking">
<div class="exam-timer">
<span>剩余时间: {{ formatTime(remainingMinutes, remainingSeconds) }}</span>
</div>
<div class="exam-content">
<el-row :gutter="20">
<el-col :span="16">
<div class="questions-area">
<div v-for="(question, index) in questions" :key="question.id"
class="question-card" >
<div class="question-content">
<span class="question-number">{{ index + 1 }}.</span>
<span class="question-type">{{ getTypeLabel(question.type) }}</span>
<p v-html="question.content"></p>
</div>
<!-- 单选题 -->
<el-radio-group v-if="question.type === 'SINGLE'"
v-model="answers[question.id]">
<el-radio v-for="(option, oi) in parseOptions(question)"
:key="oi" :label="option.key">
{{ option.key }}. {{ option.value }}
</el-radio>
</el-radio-group>
<!-- 多选题 -->
<el-checkbox-group v-else-if="question.type === 'MULTIPLE'"
v-model="answers[question.id]">
<el-checkbox v-for="(option, oi) in parseOptions(question)"
:key="oi" :label="option.key">
{{ option.key }}. {{ option.value }}
</el-checkbox>
</el-checkbox-group>
<!-- 判断题 -->
<el-radio-group v-else-if="question.type === 'JUDGE'"
v-model="answers[question.id]">
<el-radio label="true">正确</el-radio>
<el-radio label="false">错误</el-radio>
</el-radio-group>
</div>
</div>
</el-col>
<el-col :span="8">
<div class="sidemenu">
<div class="question-nav">
<div v-for="(question, index) in questions"
:key="question.id"
class="nav-item"
:class="getNavClass(question.id, index)">
{{ index + 1 }}
</div>
</div>
<el-button type="success" class="submit-btn"
@click="submitExam">
交卷
</el-button>
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
export default {
data() {
return {
examId: this.$route.params.id,
questions: [],
answers: {},
timer: null,
duration: 0,
remainingTime: 0,
questionMap: {}
}
},
computed: {
remainingMinutes() {
return Math.floor(this.remainingTime / 60)
},
remainingSeconds() {
return this.remainingTime % 60
}
},
mounted() {
this.fetchExamQuestions()
this.startTimer()
// 防止用户退出
window.onbeforeunload = () => {
return '考试进行中,确定要离开吗?'
}
},
beforeDestroy() {
clearInterval(this.timer)
window.onbeforeunload = null
},
methods: {
async fetchExamQuestions() {
const res = await this.$http.get(`/api/exam/${this.examId}/questions`)
this.questions = res.data
this.duration = res.data.duration
this.remainingTime = this.duration * 60
// 初始化答案
this.questions.forEach(q => {
if (q.type === 'MULTIPLE') {
this.$set(this.answers, q.id, [])
}
})
},
startTimer() {
this.timer = setInterval(() => {
this.remainingTime--
if (this.remainingTime <= 0) {
clearInterval(this.timer)
this.submitExam()
}
}, 1000)
},
parseOptions(question) {
return JSON.parse(question.options)
},
getNavClass(questionId, index) {
if (this.answers[questionId] &&
(this.answers[questionId].length > 0 ||
this.answers[questionId] !== '')) {
return 'answered'
}
return 'unanswered'
},
async submitExam() {
const confirmSubmit = await this.$confirm('确定要交卷吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(() => false)
if (!confirmSubmit) return
// 格式化答案
const formattedAnswers = this.questions.map(q => ({
questionId: q.id,
answer: Array.isArray(this.answers[q.id])
? this.answers[q.id].sort().join(',')
: this.answers[q.id] || ''
}))
try {
await this.$http.post('/api/exam/submit', {
examId: this.examId,
answers: formattedAnswers
})
this.$message.success('交卷成功!')
this.$router.push(`/exam/${this.examId}/result`)
} catch (error) {
this.$message.error('交卷失败,请重试')
}
},
formatTime(minutes, seconds) {
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
}
}
}
</script>
配置文件
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/exam_system?characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
jwt:
secret: your-jwt-secret-key
expiration: 86400000
server:
port: 8080
系统特色功能
随机组卷功能
@Service
public class PaperGeneratorService {
public List<Question> generatePaper(PaperConfig config) {
List<Question> paperQuestions = new ArrayList<>();
// 按难度比例随机选取题目
Map<Difficulty, Integer> difficultyConfig = config.getDifficultyRatio();
for (Map.Entry<Difficulty, Integer> entry : difficultyConfig.entrySet()) {
List<Question> questions = questionMapper.selectRandomQuestions(
entry.getKey(),
entry.getValue()
);
paperQuestions.addAll(questions);
}
// 乱序排列
Collections.shuffle(paperQuestions);
return paperQuestions;
}
}
防作弊功能
@Component
public class AntiCheatingService {
private static final int MAX_IP_CHANGE_COUNT = 3;
private static final long MAX_TIME_CHANGE_THRESHOLD = 5 * 60 * 1000;
@Cacheable(value = "student-info", key = "#studentId")
public MonitoringResult monitorStudent(Long studentId) {
MonitoringResult result = new MonitoringResult();
// 1. 检测切换窗口
result.setWindowSwitchCount(detectWindowSwitch(studentId));
// 2. 检测IP变化
result.setIpChangeCount(detectIpChanges(studentId));
// 3. 检测答题速度异常
result.setAbnormalSpeed(detectAbnormalSpeed(studentId));
// 4. 检测复制粘贴行为
result.setCopyCount(detectCopyOperations(studentId));
return result;
}
}
成绩分析报表
@RestController
@RequestMapping("/api/analysis")
public class AnalysisController {
@GetMapping("/student/{studentId}")
public Result<StudentAnalysis> studentAnalysis(@PathVariable Long studentId) {
// 学生历次考试成绩趋势
List<ExamResult> results = resultMapper.selectList(
new LambdaQueryWrapper<ExamResult>()
.eq(ExamResult::getStudentId, studentId)
.orderByAsc(ExamResult::getSubmitTime)
);
StudentAnalysis analysis = new StudentAnalysis();
analysis.setScoreTrend(results.stream()
.map(r -> new ScoreTrend(r.getSubmitTime(), r.getScore()))
.collect(Collectors.toList()));
// 知识点掌握情况雷达图
analysis.setKnowledgeRadar(analyzeKnowledgePoints(studentId));
return Result.success(analysis);
}
}
部署与运维
Docker部署配置
# Dockerfile FROM openjdk:11-jre-slim WORKDIR /app COPY target/exam-system-*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
# docker-compose.yml
version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: exam_system
ports:
- "3306:3306"
volumes:
- ./data/mysql:/var/lib/mysql
redis:
image: redis:6.0
ports:
- "6379:6379"
backend:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/exam_system
SPRING_REDIS_HOST: redis
系统优化建议
-
技术优化:
- 使用Redis缓存热点数据(考试题目)
- 使用消息队列处理批量阅卷
- 数据库读写分离
-
业务优化:
- 添加在线答疑功能
- 支持多种考试类型(公开课、练习模式)
- 增加错题本功能
-
用户体验:
- 支持移动端适配
- 添加答题卡模式
- 实时显示答题进度
这个完整的Java考试系统案例涵盖了从需求分析、数据库设计、接口开发到前端实现的完整流程,可以直接作为毕业设计或企业项目的参考实现。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播