51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring Boot结合录屏技术实现考试系统回放与复查功能

本专题将深入探讨考试系统中常见的复杂技术问题,并提供基于Spring Boot 3.x的解决方案。涵盖屏幕切换检测与防护、接打电话识别处理、行为监控摄像头使用、网络不稳定应对等,每篇文章详细剖析问题并提供实际案例与代码示例,帮助开发者应对挑战,提升考试系统的安全性、稳定性与用户体验。

Spring Boot结合录屏技术实现考试系统回放与复查功能

考试系统中,一项非常重要的功能就是考试过程的回放与复查功能。这项功能能够让教师在考试结束后,复查学生的考试过程,发现并处理考试中的违规行为,有利于维护考试的公平与公正。本文就如何使用 Spring Boot 结合录屏技术实现这个功能进行深入的讲解。

考试录屏回放与违规行为复查

在线考试正在得到越来越广泛的应用,它解决了传统考试中场地限制、时间限制等方面的问题,使得考试过程更加便捷和高效。然而,与此同时,如何有效地防止和处理考试中的不正当行为,特别是如作弊等违规行为,成为了一个需要特别去考虑和解决的问题。

传统的线下考试中,教师可以通过直接的身体存在来感知并阻止学生的违规行为,例如偷看小抄、交头接耳等。然而,这在在线考试中的情况却截然不同。由于考试全程通过电脑进行,学生可能会利用各种手段试图进行作弊,例如查阅网络资料、使用外挂软件等。对于教师来说,由于无法实际观察到学生考试时的情况,显然无法像线下考试那样直接阻止这些违规行为。

考试录屏技术的引入,就是为了解决这个问题。考试录屏,顾名思义,就是在考试过程中,对学生的电脑屏幕进行实时的录制。通过这种方式,教师就能像观看电影一样,观看学生的考试过程。这不仅可以帮助教师发现并证实作弊行为,还可以帮助教师了解学生在考试过程中的表现,例如答题的思路、时间的分配等。

然而,单纯的考试录屏并不能完全满足需求。首先,一个完整的考试过程可能会持续几个小时,对于教师来说,花那么长的时间去回放录屏显然是不现实的。其次,即使教师愿意花时间去回放录屏,但在几个小时的视频中找到准确的作弊行为,也是非常困难的。因此,我们需要引入一个能够高效地进行回放和复查的机制。

如此看来,考试录屏回放与违规行为复查不单单是提高考试公正性的需求,也是提高教师工作效率的需求。这种需求的存在,就需要我们在技术实现上提供相应的解决方案。

技术实现:Spring Boot结合录屏技术,视频存储与检索

为了实现考试录屏的功能,我们将使用Spring Boot结合录屏SDK。在Java系统中,录屏功能常常使用selenium或ffmpeg等工具进行实现。这里我们以ffmpeg为例进行详细介绍。ffmpeg是一个非常强大的多媒体处理工具,支持非常多的格式,并提供了丰富的视频处理功能,包含了视频录制。

首先,我们需要在pom.xml中引入ffmpeg相关的依赖。以下是将ffmpeg引入到SpringBoot应用中的pom配置:

<!-- ffmpeg -->
<dependency>
  <groupId>net.bramp.ffmpeg</groupId>
  <artifactId>ffmpeg</artifactId>
  <version>0.6.2</version>
</dependency>

在Spring Boot应用中,我们需要创建一个专门负责录屏的服务类 ScreenRecordService。在这个类中,我们需要提供开始录屏和停止录屏的方法。

然后,在我们应用的配置文件application.properties里面,我们需要定义录屏的相关配置:

# 录屏文件储存路径
record.file.path=/path/to/record/files
# 录屏质量(越高质量越好,但是文件大小也会越大)
record.quality=23

在实现了录屏功能后,我们需要对视频文件进行储存和检索。在Spring Boot中,我们可以使用Spring Data JPA来对录屏信息持久化存储,它可以非常方便的实现数据的CRUD操作。而对于视频文件本身,考虑到文件大小,我们可以将其存储在文件系统中。

记录的元数据我们可以设置为一个实体类,其中包含了录屏的文件名、录屏开始时间、结束时间,对应学生id等重要信息,以便于后续进行检索和回放。

以下是ScreenRecord实体类:

@Entity
public class ScreenRecord {
    @Id
    @GeneratedValue
    private Long id;
    private String filename;
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private Long studentId;

    // 省略 getter 和 setter 方法
}

有了这个实体类,我们就可以在数据库中存储和检索录屏信息了。以下是ScreenRecordRepository接口:

@Repository
public interface ScreenRecordRepository extends JpaRepository<ScreenRecord, Long> {
    List<ScreenRecord> findByStudentId(Long studentId);
}

这样,我们就实现了录屏的基本功能,并且可以方便地存储和检索录屏信息了。在下文中,我们还将介绍如何提供回放功能,以及如何进行录屏的复查。

提供便捷的回放与标记功能,辅助人工复查

在实现了录屏功能之后,我们还需要提供一个便捷的方式让教师可以方便地回放考试过程。这就需要我们提供一个回放接口。通过调用这个接口,教师可以便捷地查看学生的考试过程。

同样的,我们也需要提供一个标记功能。当教师在复查过程中发现有违规行为发生时,可以通过这个功能在录屏视频中进行标记。待复查结束后,系统病可以根据这些标记生成一个违规行为报告,由教师进一步处理。

实现录屏回放与复查功能

我们通过Spring Boot实现录屏的功能后,下一步就是实现录屏的回放与复查功能。我们的目标是让教师能流畅地查看录屏的视频,并且他们可以在任何视频的时刻点上添加标记,以便于后续的违规行为复查。

在Spring Boot中,我们可以通过StreamingResponseBody返回流媒体文件。它可以将大文件以流的形式进行逐段传输,否则整个文件需要首先完全加载到内存中,这会极大地消耗服务器资源。

以下是一个返回录屏视频的Controller,通过调用此接口,前端可以流式的获取到视频文件:

@RestController
public class VideoStreamingController {

    @GetMapping("/streaming-record/{recordId}")
    public ResponseEntity<Resource> streamVideo(@PathVariable Long recordId, @Autowired ScreenRecordRepository screenRecordRepository) {

        // 从数据库中检索出录屏记录
        ScreenRecord record = screenRecordRepository.getOne(recordId);

        // 构建录屏文件路径
        Path path = Paths.get("/path/to/record/files/" + record.getFileName());
        Resource resource;
        try {
            resource = new InputStreamResource(Files.newInputStream(path));

            // 以流的形式返回录屏文件
            return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
                    .contentType(MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM))
                    .body(resource);
        } catch (IOException e) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "无法找到录屏文件!");
        }
    }
}

在这段代码中,我们根据传入的recordId从数据库中查找到对应的录屏信息,然后根据文件名构造出录屏文件的路径,通过InputStreamResource将文件变为流,再将这个流作为ResponseEntity的body返回前端。

在实现了基础的录屏播放功能之后,我们还需实现复查标记的功能。下面是一个标记复查的Controller:

@RestController
public class ExamReviewController {

    @Autowired
    private ExamReviewService examReviewService;

    @PostMapping("/exam-review/mark")
    public ResponseEntity<Void> markViolation(@RequestBody ViolationMarkDTO violationMarkDTO) {

        examReviewService.markViolation(violationMarkDTO);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

以下是一个简单但功能完整的ExamReviewService类中的markViolation方法。

在ExamReviewService类中,我们对违规行为进行了标记。标记时,我们需要记录违规的时间点、违规的类型以及相关的备注信息。

这里我们先定义一下ViolationMarkDTO实体:

public class ViolationMarkDTO {
    private Long studentId;
    private Long recordId;
    private String violationTime;
    private String violationType;
    private String remarks;

    // 省略 getter、setter 方法
}

然后定义一个ExamReviewService服务类,并在类中实现markViolation方法:

@Service
public class ExamReviewService {

    @Autowired
    private ViolationMarkRepository violationMarkRepository;

    public void markViolation(ViolationMarkDTO violationMarkDTO) {
        ViolationMark violationMark = new ViolationMark();

        // 从DTO实体中获取信息,并储存到持久化对象中
        violationMark.setStudentId(violationMarkDTO.getStudentId());
        violationMark.setRecordId(violationMarkDTO.getRecordId());
        violationMark.setViolationTime(violationMarkDTO.getViolationTime());
        violationMark.setViolationType(violationMarkDTO.getViolationType());
        violationMark.setRemarks(violationMarkDTO.getRemarks());

        // 将违规标记存储到数据库中
        violationMarkRepository.save(violationMark);
    }
}

这个markViolation方法接收一个ViolationMarkDTO实体作为参数,这个实体包含了教师在复查时提交的违规信息。然后,我们将这些信息从DTO实体中获取出来,并储存到持久化对象ViolationMark中。最后,我们通过ViolationMarkRepository将这个持久化对象保存到数据库中。

以下是一段使用Vue实现的,教师在复查时对违规行为进行了标记的前端部分代码:

假设我们已经有了标签播放录屏视频,在视频下方有一个表单用于标记违规行为。在Vue组件中,我们可以这样实现:

<template>
    <div>
        <video ref="videoPlayer" src="url-to-record" controls></video>
        <form @submit.prevent="submitViolation">
            <label>
                违规类型:
                <select v-model="violationType">
                    <option v-for="type in violationTypes" :value="type">{{ type }}</option>
                </select>
            </label>
            <label>
                备注:
                <textarea v-model="remarks"></textarea>
            </label>

            <button type="submit">提交</button>
        </form>
    </div>
</template>

<script>
import axios from 'axios';

export default {
    data() {
        return {
            violationTypes: ['作弊', '离开监考区域', '其他'],
            violationType: '作弊',
            remarks: ''
        };
    },
    methods: {
        submitViolation() {
            const currentIndex = this.$refs.videoPlayer.currentTime;
            const violationTime = this.formatTime(currentIndex);
            
            axios.post('/exam-review/mark', {
                studentId: 123,    // 假设学生ID是123,实际情况应从某个地方取得
                recordId: 456,     // 假设录屏ID是456,实际情况应从某个地方取得
                violationTime,
                violationType: this.violationType,
                remarks: this.remarks
            }).then(() => alert('提交成功!'));
        },
        formatTime(seconds) {
            // 格式化时间,将秒数转化为 HH:mm:ss 格式
            let h = Math.floor(seconds / 3600);
            let m = Math.floor((seconds - h * 3600) / 60);
            let s = Math.floor(seconds - h * 3600 - m * 60);

            h = h < 10 ? '0' + h : h;
            m = m < 10 ? '0' + m : m;
            s = s < 10 ? '0' + s : s;

            return h + ':' + m + ':' + s;
        }
    }
}
</script>

在这段代码中,当教师点击"提交"按钮后,会触发submitViolation方法,该方法首先获取当前视频播放器的播放时间,然后通过Vue的双向绑定获取页面上教师选择的违规类型以及填写的备注,并将这些信息以POST请求的方式发送到后端。

这样,教师就可以在录屏视频的任何一个位置添加他认为的违规标记,并随时提交。后端接收到这些信息后,便可以在数据库保存下来,供将来进行问题的追踪和调查。

存储优化,保证视频完整性与清晰度

在实现录屏功能时,我们需要特别注意录屏视频的存储问题。由于视频文件通常较大,如果没有进行适当的优化,可能会导致存储空间不足,甚至影响系统的正常运行。此外,我们还要保证视频的完整性与清晰度,使得复查过程可以准确无误。

为了解决存储问题,我们可以使用如下方法:

  • 选择适合的视频编码方式,如 H.264 等,这可以大大降低视频文件的大小,同时保证视频质量。

  • 合理设计存储架构,如使用分布式文件系统,或者云存储服务,这可以有效扩展存储空间,同时保证数据的安全性和可用性。

  • 定期清理无用的视频文件,如已经复查过的录屏文件等,这可以有效利用存储资源。

本文讲述了后端和前端如何实现教师在复查阶段标记学生违规行为的方案。后端通过ExamReviewService类的markViolation方法保存违规信息。前端则使用Vue.js创建的交互式表单,使教师在观看学生录屏时即时标记并提交违规行为,有效管理违规问题,便于未来的问题追溯和解决。


赞(3)
未经允许不得转载:工具盒子 » Spring Boot结合录屏技术实现考试系统回放与复查功能