SpringBoot+Vueに基づくインテリジェントなオンライン試験システムの設計と実装

著者のホームページ:千羽鶴のプログラミング

著者について: Java、フロントエンド、Python は長年にわたって開発されており、シニア エンジニア、プロジェクト マネージャー、アーキテクトとして働いてきました。

主な内容:Javaプロジェクト開発、Pythonプロジェクト開発、大学データ・AIプロジェクト開発、MCUプロジェクト設計、インタビュー技術整理、最新技術共有

お気に入り、いいね、迷わず作者フォローすると良いです

記事の最後にあるソースコードを入手してください

品番:BS-GX-064

序文:

コンピュータやネットワーク技術の急速な発展に伴い、イントラネットアプリケーションが世界中で普及し、情報化社会への急速な進展が見られる今日、情報自動化の役割も増大しています。現在、さまざまなレベルの試験が存在しており、試験の受付など、受験者が指定された場所に順番に赴かなければならないなど、手続きが煩雑であるだけでなく、手作業による作業が主流となっています。面倒なだけでなく作業効率も非常に悪く、天候や交通状況など様々な要因に左右されます。手動管理には依然として多くの欠点があり、避けられない人的要因により、データの欠落や誤検知が発生します。コンピュータによる情報管理には、大容量、高速性など多くの利点があり、提供される情報はタイムリーかつ迅速に処理されます。

このシステムはSpringBootフレームワークをベースとしたB/Sモードで設計されており、フロントエンドページはVue.jsで開発され、データベースにはMySQLが使用されています。IDEA をフロントエンドおよびバックエンド開発ツールとして使用し、mybatis をデータベース管理ツールとしてデータベースと対話するために使用します。

オンライン試験は、試験用紙の印刷コストを節約し、試験問題の採点や統計の採点にかかる教師の負担を軽減し、教育リソースを節約し、試験プロセスをスピードアップし、情報処理におけるコンピュータの利点を最大限に発揮することができます。試験結果等を把握することで、人的資源、物的資源、財政的資源を節約するだけでなく、労働効率も向上します。オンライン試験システムは、従来の時間と場所を固定した試験モードの限界をはるかに超え、学生と教師に大きな利便性をもたらします。オンライン試験は、試験用紙の印刷コストを節約し、試験問題の採点や統計の採点にかかる教師の負担を軽減し、教育リソースを節約し、試験プロセスをスピードアップし、情報処理におけるコンピュータの利点を最大限に発揮することができます。試験結果等を把握することで、人的資源、物的資源、財政的資源を節約するだけでなく、労働効率も向上します。

1. 環境紹介

ロケール: Java: jdk1.8

データベース: MySQL: mysql5.7

アプリケーションサーバー: Tomcat: tomcat8.5.31

開発ツール: IDEA または eclipse

開発技術:Springboot+Vue

2. プロジェクト紹介

コンピュータ技術とネットワーク技術の継続的な発展に伴い、教育を支援し、教育の質を向上させるためにコンピュータを使用することは将来的に避けられない傾向です。コンピュータは日常の仕事や生活のあらゆる側面に浸透しており、私たちの勉強や仕事の右腕となっています。あらゆる階層の人々がコンピューターを使用して、非常に多くの複雑なタスクを実行しています。現在、私たちはコンピューターを使用してインテリジェントなオンライン試験システムを研究し、多くの大学生や教師にとって便利なプラットフォームを構築しています。試験制度は教育現場に欠かせないものですが、従来の紙ベースの試験・評価方法は、効率が低い、機密性が低い、時間がかかりすぎるなどの欠点があり、原因 多数のファイルとデータにより、試験問題の修正、検索、更新、保守に多くの困難が生じています。コンピュータを使用して学生をテストすることには、紙ベースのテストでは達成できない利点があります。便利な検索、高い信頼性、良好な機密性、長寿命などの利点により、学生の試験効率が大幅に向上します。もちろん、試験システムにコンピュータを導入することによるデメリットもありますが、教育と試験を分離した試験システムの開発・設計を研究する過程で、デメリットの影響を最小限に抑えることも必要です。

このテーマの研究内容は、大学における教育と試験のための独立した試験システムを開発・設計し、教師と学生がネットワークを介してオンライン試験や学習評価を実施できるようにすることです。

この記事は、Springboot に基づいたインテリジェントなオンライン試験システムのセットを設計および開発することを目的としており、インテリジェントなオンライン試験システムのアーキテクチャを詳細に分析し、各モジュール間の関係を確立し、問題バンク管理、科目管理、論文構成について説明します。管理、試験機能、判定など、試験用紙機能やスコア管理などの機能モジュールの分析、設計、実装、テストにより、インテリジェントなオンライン試験システムの完全なセットが完成します。

 システムでは、管理者 (教師) ロールと受験者 (学生) ロールの 2 つのユーザー ロールを設計します。管理者は、バックグラウンド管理インターフェイスに入り、ユーザー、テスト用紙、タスク、科目、成績、メッセージ センターの送信、ログ センターの管理などを管理できます。学生は、対応する試験を受けたり、オンラインで回答したり、間違った質問セットを表示したりするために、自然に学生インターフェイスに入り、他の操作。システムの機能ブロック図を図 3-1 に示します。

図 3-1 システム機能モジュール図

受験者は、テスト用紙を使用して、質問に回答したり、演習を行ったり、テスト用紙を表示したり、テスト後にテスト結果 (つまり、関連するテスト記録) を確認したりできます。システムは、学生の間違った質問セットを収集し、学生は間違った問題を修正することもできます。ユーザー関数のユースケース図を図 3-2 に示します。

図 3-2 ユーザー関数のユースケース図

管理者はシステムの組み込みアカウントを介してログインし、管理者アカウントはユーザー管理、質問管理、タスク管理、教育管理、パフォーマンス管理、メッセージ センターの送信、およびバックグラウンドでのログ センターの表示を実行できます。管理者機能のユースケース図を図 3-3 に示します。

図 3-3 管理者機能のユースケース図

このシステムには、ユーザーモジュール、ログインおよび登録モジュール、検査機能モジュール、ストレージモジュール、メッセージプッシュモジュール、検索モジュール、バックグラウンド管理モジュールの7つの機能モジュールがあり、主な機能は次のように分析されます。

1. ユーザーモジュール機能

表 3-1 ユーザーモジュールの機能説明

関数名

機能説明

ユーザー登録

ユーザーはテスト システムにアクセスして最初に登録します

個人情報を閲覧する

ユーザーはアバターの変更など、自分の情報を変更します。

パスワードを変更する

ユーザーのログインパスワードを変更する

ニュースを見る

他のユーザーからのメッセージのリストを表示する

2. 登録モジュールにログインします。

表 3-2 ログイン登録モジュールの機能説明

関数名

機能説明

ロールログイン

ユーザーはフォアグラウンド インターフェイスにログインし、管理者はバックグラウンド インターフェイスにログインします。

登録

ユーザーは特定のアカウントを登録して管理する必要があります

3. 試験機能モジュール

表 3-3 検査機能モジュールの機能説明

関数名

機能説明

剥離試験紙

管理者が試験問題を公開します

件名一覧

数学や英語などのテスト科目の種類を公開する

試験の種類

共通模擬試験問題と定期リリース試験問題

候補者試験

受験者は試験を受けるようメッセージを受け取ります

候補者の練習

受験者は通常、教師が発行する練習問題を練習できます。

4. ストレージモジュール

表 3-4 ストレージモジュールの機能の説明

関数名

機能説明

オンラインストレージ

Qiniu クラウド オンライン ストレージを活用する

5. メッセージプッシュモジュール

表 3-5 メッセージプッシュモジュールの機能説明

関数名

機能説明

メッセージを送る

管理者は試験情報を通知するメッセージをユーザーに公開します

メッセージ受信

ユーザーは管理者からの情報通知を受け取ることができます

6. 検索モジュール

表 3-6 検索モジュールの機能説明

関数名

機能説明

キーワード検索

分析投稿のタイトルをキーワードとして使用して、該当するコンテンツを検索します

7. バックグラウンド管理モジュール

表 3-7 バックグラウンド管理モジュールの機能説明

関数名

機能説明

役割管理

学生および管理者のリスト情報を変更および管理する

ボリューム管理

試験用紙を公開する

タスク管理

タスクリストを変更してタスクを作成できます

主題の管理

件名リスト情報の変更および管理

パフォーマンス管理

受験者の成績に関するお問い合わせ

クエスチョンバンク管理

質問を作成し、トピック カテゴリをクエリし、トピックを公開できます。

メッセージセンター

メッセージを送信するためにメッセージ リストを変更する

8. レコメンデーションモジュール

表 3-8 バックグラウンド管理モジュールの機能説明

関数名

機能説明

ユーザー管理

ユーザー情報の管理。ユーザーのクエリ、変更、無効化

投稿管理を共有する

プラットフォーム内の共有投稿を検索して変更または削除します

通知管理

新しい通知の公開、既存の通知の変更および削除に使用されます

レポート管理

ユーザーによって送信された報告情報の表示および処理

3.2.2 性能要件

このシステムはB/Sアーキテクチャに基づいており、ユーザーはブラウザを通じてアクセスしてサービスを取得するため、ユーザーエクスペリエンスを確保するために比較的安定したパフォーマンスが要求されます。

1.データの精度

バックエンドプログラムがデータの追加、削除、変更操作を行う場合、プログラム上の理由による操作の失敗には対応していません。

バックエンド プログラムがデータを追加する場合、複数回の追加や繰り返しの追加はサポートされません。

バックエンド プログラムがデータを削除する場合、複数の削除されたデータはサポートされません。

バックエンドプログラムがデータを削除する場合、関連するデータを完全に削除する必要があります。削除できない場合は、リマインドしてください。

バックエンドプログラムがデータ変更を実行する場合、それに対応する精度を維持する必要もあります。

時間特性:

追加や削除などの操作を実行する場合、データベースの応答時間は 2 秒以内である必要があります。

ログイン登録の応答時間は 3 秒以下です。

Web ページの更新応答時間 <= 2 秒。

データレンダリングの応答時間 <= 0.5 秒。

データ更新応答時間 <= 0.5 秒。

共有投稿のクエリに対する応答時間は 1 秒以下です。

人気のある推奨事項の応答時間は 1 秒以下です。

2.セキュリティ

バックエンド サーバーには、安全で信頼性の高いファイアウォールの確立が必要です。

バックエンド サーバー サービスのセキュリティを確保し、サービスへの匿名アクセスを禁止します。

データベース内の受験者(生徒)または管理者(教師)のパスワードデータは、MD5暗号化が必要です。

3.サポートソフトウェア

(1) クライアントソフトウェア:

オペレーティング システム: Linux、Windows 7/10;

ブラウザ: Chrome、Fire Fox、Edge。

(2) サーバーソフトウェア:

オペレーティング システム: Windows Server 2012/2016、Windows 7/10、Linux。

Java バージョン: 1.8;

データベースのバージョン: MySQL5.7 以降。

機能とサービス: Qiniu クラウド ストレージ サービス。

三、システム表示

5.1ユーザーモジュール

5.1.1登録とログイン

前端登录与注册页面由login.vue实现,用户信息由userInfo.vue实现。用户首先需要输入用户名和邮箱,之后点击发送验证码,前端会将用户名和邮箱通过/api/sendCode提交到后端。后端接受到数据之后,首先会验证邮箱是否符合格式,邮箱是否已经被注册,如果条件成立,则返回相关提示信息。否则将生成验证码,通过邮件发送至用户邮箱,同时将邮箱和验证码存储于session中。之后用户需要将其他信息填写完毕,并且输入验证码,点击注册,前端会通过/api/register接口将数据提交到后端。后端收到数据后,首先会通过提交信息的邮箱从session中读取之前存储的验证码并进行对比,如果不一致,则返回验证码无效提示信息,否则继续业务。之后会验证邮箱是否符合规范,以及是否被注册,如果验证通过,则后端调用服务层类userService的register方法添加用户,register方法首先会将用户的密码进行MD5加密,填充注册时间,用户状态等信息,然后通过持久层类userMapper的方法将用户信息提交至数据库。提交成功之将创建用户的文件仓库,通过调用fileStoreService的 createFileStore方法创建对应用户的文件仓库并提交到数据库。界面实现效果如图5-1所示。

完成注册之后用户就可以登录了。输入用户名和密码之后点击登录,前端会将携带用户名与密码通过/api/login接口提交至后端,后端调用服务层类userService的login方法来处理数据。首先会将用户的明文密码使用MD5加密,之后通过持久层类userMapper的方法去数据库中查询是否存在对应用户名的用户,然后对比密码是否正确,并返回相应结果至控制层。如果账户密码正确,则将查询到的用户数据存储于session中,并且生成token提交至数据库中。之后将提示信息与token返回至前端,前端会将token存储于cookie中,以保持登录状态。界面实现效果如图5-2所示。

用户完成登录之后,将跳转至网盘界面,同时通过/api/getTokenVerity接口验证token是否有效,然后通过/api/getLoggedUser接口向后端的session中获取当前登录用户信息,并存储于cookie中。

图5-1 注册界面

图5-2 登录界面

5.1.2 个人信息

用户信息页面由userinfo.vue实现。登入系统之后,用户可以通过右上角下拉菜单进入用户信息页面。前端会携带登录用户信息,通过/api/u/getUser接口向后端请求当前用户信息,前端返回信息之后会将用户信息渲染至页面上。界面实现效果如图5-3所示。

图5-3 个人信息界面

5.1.3 查看消息

修改密码需要输入原密码和新密码,点击确定之后前端会通过/api/u/ resetPass接口向后端发送请求,携带用户ID和新旧密码。后端收到请求之后会调用服务层类userService的resetPass方法来处理业务。首先会判断原密码是否正确,然后检查新旧密码是否一致,如果一致则返回提示信息,否则将新密码使用MD5加密之后提交至数据库,然后向前端返回成功更改提示信息。界面实现效果如图5-4所示。

图5-4 查看信息界面

5.2 登录模块

5.2.1 角色登录

网盘界面由files.vue实现。用户登入之后会跳转至网盘界面,用户可在此查看网盘内的文件并进行管理。点击文件夹即可查看对应文件夹,前端会向/api/f/getDir接口发出请求,携带文件仓库与目标文件夹参数,后端获取对应文件夹下目录的数据返回至前端,前端根据后端的数据重新渲染目录,并记录用户当前路径信息。点击上一级或根目录按钮,前端会读取存储的路径信息,通过/api/f/getDir接口向后端请求对应目录的数据并再次渲染,以返回上一级目录。界面实现效果如图5-7所示。

图5-5用户登录前台界面

图5-6 管理员登录后台界面

5.3 考试功能模块

5.3.1 发布试卷

回收站模块同样由files.vue实现用户在网盘界面删除的文件并非被真的删除了,而是移动到了回收站,这里展示的是用户文件仓库中,所有被标记为删除的文件与文件夹。选择一个或多个文件及文件夹之后,即可执行还原操作。

点击还原文件按钮后会显示路径选择窗口,选择文件夹存放的目录然后点击确定后前端调用/api/rf/recovery接口发送请求,将被还原的文件及文件夹信息传递至后端,后端调用服务层类recycleBinService的recycleOrRecovery方法处理业务。根据请求携带的文件及文件夹信息分别处理,首先与还原文件及文件夹数据的名称进行对比,若存在重名则返回提示信息,否则将对应文件对象重新设置为未回收状态并设置文件的新路径。而文件夹则会通过recycleFoldersFile方法并设置为还原模式进行进一步操作,以还原文件夹下所有的子文件夹以及文件。界面实现效果如图5-11所示。

图5-7发布试卷页面

5.3.2 学科列表

选择选择一个或多个文件及文件夹之后,即可删除选择的文件或文件夹,而清空操作则是直接删除对回收站下的所有文件。在回收站执行的删除的操作会删除FTP上的文件,彻底从系统中移除本文件。删除文件和清空回收站都调用/api/f/delete接口,如果执行删除操作,前端会将选择的文件及文件夹信息通过此接口发送的后端,如果是清空操作,前端则会将回收站所有的文件信息传递至后端。后端接受到请求与文件信息之后对文件及文件夹进行分别处理,文件夹通过调用服务层folderService类删除数据库信息。文件则调用服务层fileService类deleteFTPFIle方法进行处理。因为FTP上的一个物理文件很可能在逻辑上关联了多条数据库信息,如果贸然删除FTP上的物理文件可能导致其他保存了次文件的用户将无法下载该文件,所以deleteFTPFIle方法在删除文件之前首先会检查该文件是否有多个关联数据库条目。进入deleteFTPFIle方法后,首先通过文件ID获取文件对象,之后通过文件对象的FTP地址从数据库中查询文件,再通过文件ID从数据库中查找分享帖,如果查到到相同FTP路径的文件大于1,以及查找到存在分享此文件的分享帖,则仅从数据库中删除数据库信息,否则调用FtpUtil类删除FTP文件。

图5-7学科列表页面

5.3.3 考试种类

选择选择一个或多个文件及文件夹之后,即可删除选择的文件或文件夹,而清空操作则是直接删除对回收站下的所有文件。在回收站执行的删除的操作会删除FTP上的文件,彻底从系统中移除本文件。删除文件和清空回收站都调用/api/f/delete接口,如果执行删除操作,前端会将选择的文件及文件夹信息通过此接口发送的后端,如果是清空操作,前端则会将回收站所有的文件信息传递至后端。后端接受到请求与文件信息之后对文件及文件夹进行分别处理,文件夹通过调用服务层folderService类删除数据库信息。文件则调用服务层fileService类deleteFTPFIle方法进行处理。因为FTP上的一个物理文件很可能在逻辑上关联了多条数据库信息,如果贸然删除FTP上的物理文件可能导致其他保存了次文件的用户将无法下载该文件,所以deleteFTPFIle方法在删除文件之前首先会检查该文件是否有多个关联数据库条目。进入deleteFTPFIle方法后,首先通过文件ID获取文件对象,之后通过文件对象的FTP地址从数据库中查询文件,再通过文件ID从数据库中查找分享帖,如果查到到相同FTP路径的文件大于1,以及查找到存在分享此文件的分享帖,则仅从数据库中删除数据库信息,否则调用FtpUtil类删除FTP文件。

图5-8练习试卷页面

图5-9时段页面

5.7 后台管理模块

后台管理模块为系统管理员提供了对系统中数据进行查询与管理的平台。后台管理页面仅对管理员用户开放,管理用用户即用户等级为9的用户。用户查看此页面以及子页面时,前端会通过/api/a/verityUserLevel接口携带当前用户ID向后端验证用户是否为管理员,然后才允许继续操作。否则跳转回登录页面。

5.7.1 角色管理

用户管理由userManage.vue实现。此页面用于对系统中的用户账户进行查询与管理。当管理员进入用户管理页面,前端首先会通过/api/a/getAll接口向后端发送请求,以获取所有的用户账户数据并返回至前端,前端收到数据之后分页渲染。界面实现效果如图5-20所示。

管理员可以通过页面操作按钮来查看用户信息,也可以通过搜索栏来查找指定用户的信息。在搜索栏中输入用户名,点击查找,前端便会通过/api/a/getUserByKeyWord接口将关键词传递至后端,后端接受请求之之后将查找到的数据返回至前端,前端再将数据渲染到页面上。

当管理点击新增按钮就会显示添加用户窗口,管理员填写完相关数据之后,点击确认,前端就会将该数据通过/api/a/addUser接口提交到数据库中。点击编辑按钮会打开与添加用户窗口一致的编辑用户窗口,前端会自动将被编辑用户的数据填入输入框,管理员只需更改需要更改的数据即可,点击提交前端会通过/api/a/updateUser接口将数据更新至数据库中。以上操作完成后,后端会返回成功信息至前端,前端再次获取更新后的用户数据并渲染用户信息列表。界面实现效果如图5-21所示。

当管理员点击某个用户账户信息上的禁用按钮时,前端会弹出提示框,询问管理员是否进行操作,点击确定,前端便会通过/api/a/UpdateStatus/接口禁用此账户。禁用后,该用户就无法使用此账户来登录系统。

图5-20 角色管理界面

5.7.2 组卷管理

分享管理由postsManage.vue实现分享管理页面用于管理系统中的分享帖。当管理员进入本页面,前端首先会通过/api/a/getAllPosts接口获取所有分享帖的数据,然后渲染到页面上。

此页面也提供了按照用户昵称来检索其对应分享帖的功能,在搜索栏输入用户昵称然后点击搜索,前端就会/api/a/searchPosts接口携带搜索内容传递至后端,后端接收请求后查找数据库中的对应内容,并返回至前端。前端收到数据之后渲染到页面上。界面实现效果如图5-22所示。

共有投稿はページ上にリスト形式で表示され、管理者は投稿のタイトルをクリックして、対応する共有投稿を入力できます。または、編集ボタンと削除ボタンをクリックして投稿を操作します。編集ボタンをクリックすると、投稿編集ウィンドウが表示され、フロントエンドが入力ボックスに投稿の対応するデータを自動的に入力します。管理者が編集を終了した後、「OK」ボタンをクリックすると、フロントエンドは /api/a/edit インターフェースを介して投稿データをバックエンドに渡します。バックエンドはデータを受け入れてデータベースに送信し、フロントエンドに成功メッセージを送信すると、フロントエンドは再度新しいメッセージを要求し、情報を投稿してページにレンダリングします。インターフェイス実装の効果を図 5-23 に示します。

削除ボタンをクリックすると、フロントエンドは /api/a/deletePosts インターフェイスを介して投稿 ID を使用してバックエンドにリクエストを送信します。リクエストを受信した後、バックエンドは投稿 ID を介して特定の投稿オブジェクトを取得し、投稿オブジェクトのdeleted属性をtrueに設定します。次に、サービス層メソッドクラスnoticeServerのadd Noticeメソッドを通じて、削除された投稿の投稿に投稿が削除された旨の通知を送信します。次に、変更した投稿オブジェクトをデータベースに保存し、成功メッセージをフロントエンドに返します。フロントエンドは成功メッセージを受信した後、すべての投稿情報を再度取得して、現在のページを更新します。

図 5-22 ボリューム管理ページ

図 5-23 ポスト編集ウィンドウ

4番目、コアコード表示

package com.zlf.exam.controller.student;

import com.zlf.exam.base.BaseApiController;
import com.zlf.exam.base.RestResponse;
import com.zlf.exam.domain.TaskExam;
import com.zlf.exam.domain.TaskExamCustomerAnswer;
import com.zlf.exam.domain.TextContent;
import com.zlf.exam.domain.User;
import com.zlf.exam.domain.enums.ExamPaperTypeEnum;
import com.zlf.exam.domain.task.TaskItemAnswerObject;
import com.zlf.exam.domain.task.TaskItemObject;
import com.zlf.exam.service.*;
import com.zlf.exam.utility.DateTimeUtil;
import com.zlf.exam.utility.JsonUtil;
import com.zlf.exam.viewmodel.student.dashboard.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@RestController("StudentDashboardController")
@RequestMapping(value = "/api/student/dashboard")
public class DashboardController extends BaseApiController {

    private final UserService userService;
    private final ExamPaperService examPaperService;
    private final QuestionService questionService;
    private final TaskExamService taskExamService;
    private final TaskExamCustomerAnswerService taskExamCustomerAnswerService;
    private final TextContentService textContentService;

    @Autowired
    public DashboardController(UserService userService, ExamPaperService examPaperService, QuestionService questionService, TaskExamService taskExamService, TaskExamCustomerAnswerService taskExamCustomerAnswerService, TextContentService textContentService) {
        this.userService = userService;
        this.examPaperService = examPaperService;
        this.questionService = questionService;
        this.taskExamService = taskExamService;
        this.taskExamCustomerAnswerService = taskExamCustomerAnswerService;
        this.textContentService = textContentService;
    }

    @RequestMapping(value = "/index", method = RequestMethod.POST)
    public RestResponse<IndexVM> index() {
        IndexVM indexVM = new IndexVM();
        User user = getCurrentUser();

        PaperFilter fixedPaperFilter = new PaperFilter();
        fixedPaperFilter.setGradeLevel(user.getUserLevel());
        fixedPaperFilter.setExamPaperType(ExamPaperTypeEnum.Fixed.getCode());
        indexVM.setFixedPaper(examPaperService.indexPaper(fixedPaperFilter));

        PaperFilter timeLimitPaperFilter = new PaperFilter();
        timeLimitPaperFilter.setDateTime(new Date());
        timeLimitPaperFilter.setGradeLevel(user.getUserLevel());
        timeLimitPaperFilter.setExamPaperType(ExamPaperTypeEnum.TimeLimit.getCode());

        List<PaperInfo> limitPaper = examPaperService.indexPaper(timeLimitPaperFilter);
        List<PaperInfoVM> paperInfoVMS = limitPaper.stream().map(d -> {
            PaperInfoVM vm = modelMapper.map(d, PaperInfoVM.class);
            vm.setStartTime(DateTimeUtil.dateFormat(d.getLimitStartTime()));
            vm.setEndTime(DateTimeUtil.dateFormat(d.getLimitEndTime()));
            return vm;
        }).collect(Collectors.toList());
        indexVM.setTimeLimitPaper(paperInfoVMS);
        return RestResponse.ok(indexVM);
    }


    @RequestMapping(value = "/task", method = RequestMethod.POST)
    public RestResponse<List<TaskItemVm>> task() {
        User user = getCurrentUser();
        List<TaskExam> taskExams = taskExamService.getByGradeLevel(user.getUserLevel());
        if (taskExams.size() == 0) {
            return RestResponse.ok(new ArrayList<>());
        }
        List<Integer> tIds = taskExams.stream().map(taskExam -> taskExam.getId()).collect(Collectors.toList());
        List<TaskExamCustomerAnswer> taskExamCustomerAnswers = taskExamCustomerAnswerService.selectByTUid(tIds, user.getId());
        List<TaskItemVm> vm = taskExams.stream().map(t -> {
            TaskItemVm itemVm = new TaskItemVm();
            itemVm.setId(t.getId());
            itemVm.setTitle(t.getTitle());
            TaskExamCustomerAnswer taskExamCustomerAnswer = taskExamCustomerAnswers.stream()
                    .filter(tc -> tc.getTaskExamId().equals(t.getId())).findFirst().orElse(null);
            List<TaskItemPaperVm> paperItemVMS = getTaskItemPaperVm(t.getFrameTextContentId(), taskExamCustomerAnswer);
            itemVm.setPaperItems(paperItemVMS);
            return itemVm;
        }).collect(Collectors.toList());
        return RestResponse.ok(vm);
    }


    private List<TaskItemPaperVm> getTaskItemPaperVm(Integer tFrameId, TaskExamCustomerAnswer taskExamCustomerAnswers) {
        TextContent textContent = textContentService.selectById(tFrameId);
        List<TaskItemObject> paperItems = JsonUtil.toJsonListObject(textContent.getContent(), TaskItemObject.class);

        List<TaskItemAnswerObject> answerPaperItems = null;
        if (null != taskExamCustomerAnswers) {
            TextContent answerTextContent = textContentService.selectById(taskExamCustomerAnswers.getTextContentId());
            answerPaperItems = JsonUtil.toJsonListObject(answerTextContent.getContent(), TaskItemAnswerObject.class);
        }


        List<TaskItemAnswerObject> finalAnswerPaperItems = answerPaperItems;
        return paperItems.stream().map(p -> {
                    TaskItemPaperVm ivm = new TaskItemPaperVm();
                    ivm.setExamPaperId(p.getExamPaperId());
                    ivm.setExamPaperName(p.getExamPaperName());
                    if (null != finalAnswerPaperItems) {
                        finalAnswerPaperItems.stream()
                                .filter(a -> a.getExamPaperId().equals(p.getExamPaperId()))
                                .findFirst()
                                .ifPresent(a -> {
                                    ivm.setExamPaperAnswerId(a.getExamPaperAnswerId());
                                    ivm.setStatus(a.getStatus());
                                });
                    }
                    return ivm;
                }
        ).collect(Collectors.toList());
    }
}
package com.zlf.exam.controller.student;

import com.github.pagehelper.PageInfo;
import com.zlf.exam.base.BaseApiController;
import com.zlf.exam.base.RestResponse;
import com.zlf.exam.domain.Message;
import com.zlf.exam.domain.MessageUser;
import com.zlf.exam.domain.User;
import com.zlf.exam.domain.UserEventLog;
import com.zlf.exam.domain.enums.RoleEnum;
import com.zlf.exam.domain.enums.UserStatusEnum;
import com.zlf.exam.event.UserEvent;
import com.zlf.exam.service.AuthenticationService;
import com.zlf.exam.service.MessageService;
import com.zlf.exam.service.UserEventLogService;
import com.zlf.exam.service.UserService;
import com.zlf.exam.utility.DateTimeUtil;
import com.zlf.exam.utility.PageInfoHelper;
import com.zlf.exam.viewmodel.student.user.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController("StudentUserController")
@RequestMapping(value = "/api/student/user")
public class UserController extends BaseApiController {

    private final UserService userService;
    private final UserEventLogService userEventLogService;
    private final MessageService messageService;
    private final AuthenticationService authenticationService;
    private final ApplicationEventPublisher eventPublisher;

    //后台登录代码
    @Autowired
    public UserController(UserService userService, UserEventLogService userEventLogService, MessageService messageService, AuthenticationService authenticationService, ApplicationEventPublisher eventPublisher) {
        this.userService = userService;
        this.userEventLogService = userEventLogService;
        this.messageService = messageService;
        this.authenticationService = authenticationService;
        this.eventPublisher = eventPublisher;
    }

    @RequestMapping(value = "/current", method = RequestMethod.POST)
    public RestResponse<UserResponseVM> current() {
        User user = getCurrentUser();
        UserResponseVM userVm = UserResponseVM.from(user);
        return RestResponse.ok(userVm);
    }


    //后台注册代码
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public RestResponse register(@RequestBody @Valid UserRegisterVM model) {
        User existUser = userService.getUserByUserName(model.getUserName());
        if (null != existUser) {
            return new RestResponse<>(2, "用户已存在");
        }
        User user = modelMapper.map(model, User.class);
        String encodePwd = authenticationService.pwdEncode(model.getPassword());
        user.setUserUuid(UUID.randomUUID().toString());
        user.setPassword(encodePwd);
        user.setRole(RoleEnum.STUDENT.getCode());
        user.setStatus(UserStatusEnum.Enable.getCode());
        user.setLastActiveTime(new Date());
        user.setCreateTime(new Date());
        user.setDeleted(false);
        userService.insertByFilter(user);
        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent("欢迎 " + user.getUserName() + " 注册来到在线考试系统");
        eventPublisher.publishEvent(new UserEvent(userEventLog));
        return RestResponse.ok();
    }


    //后台个人信息更新代码
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public RestResponse update(@RequestBody @Valid UserUpdateVM model) {
        if (StringUtils.isBlank(model.getBirthDay())) {
            model.setBirthDay(null);
        }
        User user = userService.selectById(getCurrentUser().getId());
        modelMapper.map(model, user);
        user.setModifyTime(new Date());
        userService.updateByIdFilter(user);
        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent(user.getUserName() + " 更新了个人资料");
        eventPublisher.publishEvent(new UserEvent(userEventLog));
        return RestResponse.ok();
    }

    @RequestMapping(value = "/log", method = RequestMethod.POST)
    public RestResponse<List<UserEventLogVM>> log() {
        User user = getCurrentUser();
        List<UserEventLog> userEventLogs = userEventLogService.getUserEventLogByUserId(user.getId());
        List<UserEventLogVM> userEventLogVMS = userEventLogs.stream().map(d -> {
            UserEventLogVM vm = modelMapper.map(d, UserEventLogVM.class);
            vm.setCreateTime(DateTimeUtil.dateFormat(d.getCreateTime()));
            return vm;
        }).collect(Collectors.toList());
        return RestResponse.ok(userEventLogVMS);
    }

    @RequestMapping(value = "/message/page", method = RequestMethod.POST)
    public RestResponse<PageInfo<MessageResponseVM>> messagePageList(@RequestBody MessageRequestVM messageRequestVM) {
        messageRequestVM.setReceiveUserId(getCurrentUser().getId());
        PageInfo<MessageUser> messageUserPageInfo = messageService.studentPage(messageRequestVM);
        List<Integer> ids = messageUserPageInfo.getList().stream().map(d -> d.getMessageId()).collect(Collectors.toList());
        List<Message> messages = ids.size() != 0 ? messageService.selectMessageByIds(ids) : null;
        PageInfo<MessageResponseVM> page = PageInfoHelper.copyMap(messageUserPageInfo, e -> {
            MessageResponseVM vm = modelMapper.map(e, MessageResponseVM.class);
            messages.stream().filter(d -> e.getMessageId().equals(d.getId())).findFirst().ifPresent(message -> {
                vm.setTitle(message.getTitle());
                vm.setContent(message.getContent());
                vm.setSendUserName(message.getSendUserName());
            });
            vm.setCreateTime(DateTimeUtil.dateFormat(e.getCreateTime()));
            return vm;
        });
        return RestResponse.ok(page);
    }

    @RequestMapping(value = "/message/unreadCount", method = RequestMethod.POST)
    public RestResponse unReadCount() {
        Integer count = messageService.unReadCount(getCurrentUser().getId());
        return RestResponse.ok(count);
    }

    @RequestMapping(value = "/message/read/{id}", method = RequestMethod.POST)
    public RestResponse read(@PathVariable Integer id) {
        messageService.read(id);
        return RestResponse.ok();
    }

}

V. プロジェクトの概要

おすすめ

転載: blog.csdn.net/BS009/article/details/132079081