项目介绍 :
Spring Boot + SpringMVC + MyBatis Plus+ Mysql + druid + Vue 开发的前后端分离的在线考试系统
项目演示:
https://www.bilibili.com/video/BV1n1421Q7kf/?vd_source=11ac782881cbade0d1444685d3b0d4df
环境需要:
- 运行环境: 最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。
- IDE环境:Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以
- 数据库:MySql 5.7
- Maven:3.3以上
技术栈
前端
Vue、Axios、Element UI、Vue-Router、Vuex、ECharts
后端
Spring Boot、JWT、MyBatis-Plus、MySQL
功能结构
管理员角色:
- 首页
- 考试管理
- 题库管理
- 成绩查询
- 学生管理
- 教师管理
教师角色
- 首页
- 考试管理
- 题库管理
- 成绩查询
- 学生管理
学生角色
- 在线考试
- 试卷练习
- 留言
- 分数查看
项目预览
登录页
系统展示
部分代码
package com.rabbiter.oes.controller;
import com.rabbiter.oes.entity.Admin;
import com.rabbiter.oes.entity.ApiResult;
import com.rabbiter.oes.serviceimpl.AdminServiceImpl;
import com.rabbiter.oes.util.ApiResultHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
public class AdminController {
private AdminServiceImpl adminService;
@Autowired
public AdminController(AdminServiceImpl adminService){
this.adminService = adminService;
}
@GetMapping("/admins")
public ApiResult findAll(){
System.out.println("查询全部");
return ApiResultHandler.success(adminService.findAll());
}
@GetMapping("/admin/{adminId}")
public ApiResult findById(@PathVariable("adminId") Integer adminId){
System.out.println("根据ID查找");
return ApiResultHandler.success(adminService.findById(adminId));
}
@DeleteMapping("/admin/{adminId}")
public ApiResult deleteById(@PathVariable("adminId") Integer adminId){
adminService.deleteById(adminId);
return ApiResultHandler.success();
}
@PutMapping("/admin/{adminId}")
public ApiResult update(@PathVariable("adminId") Integer adminId, Admin admin){
return ApiResultHandler.success(adminService.update(admin));
}
@PostMapping("/admin")
public ApiResult add(Admin admin){
return ApiResultHandler.success(adminService.add(admin));
}
@GetMapping("/admin/resetPsw/{adminId}/{oldPsw}/{newPsw}")
public ApiResult resetPsw(@PathVariable("adminId") Integer adminId, @PathVariable("newPsw") String newPsw, @PathVariable("oldPsw") String oldPsw) {
return ApiResultHandler.success(adminService.resetPsw(adminId, newPsw, oldPsw));
}
}
<!-- 用户登录界面 -->
<template>
<div id="login">
<div class="bg"></div>
<el-row class="main-container">
<el-col :lg="8" :xs="16" :md="10" :span="10">
<div class="top" style="color: black">
<span class="el-icon-a-061 title"> 在线考试系统</span>
</div>
<br />
<div class="bottom">
<div class="container">
<p class="title">账号登录</p>
<el-form :label-position="labelPosition" label-width="80px" :model="formLabelAlign">
<el-form-item label="用户名">
<el-input v-model.number="formLabelAlign.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="formLabelAlign.password" placeholder="请输入密码" type="password"></el-input>
</el-form-item>
<div class="submit">
<el-button type="primary" class="row-login" @click="login()">登录</el-button>
</div>
<!-- <div class="options">
<p class="find"><a href="javascript:;">找回密码</a></p>
<div class="register">
<span>没有账号?</span>
<span><a href="javascript:;">去注册</a></span>
</div>
</div> -->
</el-form>
</div>
</div>
</el-col>
</el-row>
<el-row class="footer">
<el-col>
<!-- <p class="msg2" style="color: black;">Copyright© 忧伤大白兔</p> -->
</el-col>
</el-row>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "login",
data () {
return {
role: 2,
labelPosition: "left",
formLabelAlign: {
username: "",
password: "",
},
};
},
methods: {
//用户登录请求后台处理
login () {
if (
this.formLabelAlign.username == undefined ||
this.formLabelAlign.username == ""
) {
this.$message("请输入用户名");
return;
}
if (
!/^\d+$/.test(this.formLabelAlign.username) ||
this.formLabelAlign.username.toString().length > 10
) {
this.$message("用户名有误");
return;
}
if (this.formLabelAlign.password == "") {
this.$message("请输入密码");
return;
}
this.$axios({
url: `/api/login`,
method: "post",
data: {
...this.formLabelAlign,
},
}).then((res) => {
let resData = res.data.data;
if (resData != null) {
switch (resData.role) {
case "0": //管理员
this.$cookies.set("cname", resData.adminName);
this.$cookies.set("cid", resData.adminId);
this.$cookies.set("role", 0);
this.$router.push({ path: "/index" }); //跳转到首页
break;
case "1": //教师
this.$cookies.set("cname", resData.teacherName);
this.$cookies.set("cid", resData.teacherId);
this.$cookies.set("role", 1);
this.$router.push({ path: "/index" }); //跳转到教师用户
break;
case "2": //学生
this.$cookies.set("cname", resData.studentName);
this.$cookies.set("cid", resData.studentId);
this.$router.push({ path: "/student" });
break;
}
}
if (resData == null) {
//错误提示
this.$message({
showClose: true,
type: "error",
message: "用户名或者密码错误",
});
}
});
},
clickTag (key) {
this.role = key;
},
},
computed: mapState(["userInfo"]),
mounted () { },
};
</script>
<style lang="less" scoped>
.remind {
border-radius: 4px;
padding: 10px 20px;
display: flex;
position: fixed;
right: 20px;
bottom: 50%;
flex-direction: column;
color: #606266;
background-color: #fff;
border-left: 4px solid #409eff;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.container {
margin-bottom: 32px;
}
.container .el-radio-group {
margin: 30px 0px;
}
a:link {
color: #ff962a;
text-decoration: none;
}
#login {
font-size: 14px;
color: #000;
background-color: #fff;
}
#login .bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
overflow-y: auto;
height: 100%;
background: url("../../assets/img/loginbg.png") center top / cover no-repeat;
background-color: #b6bccdd1 !important;
}
#login .main-container {
display: flex;
justify-content: center;
align-items: center;
}
#login .main-container .top {
margin-top: 100px;
font-size: 30px;
color: #ff962a;
display: flex;
justify-content: center;
}
#login .top .icon-kaoshi {
font-size: 80px;
}
#login .top .title {
margin-top: 20px;
}
#login .bottom {
display: flex;
justify-content: center;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
#login .bottom .title {
text-align: center;
font-size: 30px;
}
.bottom .container .title {
margin: 30px 0px;
}
.bottom .submit .row-login {
width: 100%;
background-color: #04468b;
border-color: #04468b;
margin: 20px 0px 10px 0px;
padding: 15px 20px;
}
.bottom .submit {
display: flex;
justify-content: center;
}
.footer {
margin-top: 50px;
text-align: center;
}
.footer .msg1 {
font-size: 18px;
color: #fff;
margin-bottom: 15px;
}
.footer .msg2 {
font-size: 14px;
color: #e3e3e3;
margin-top: 70px;
}
.bottom .options {
margin-bottom: 40px;
color: #ff962a;
display: flex;
justify-content: space-between;
}
.bottom .options > a {
color: #ff962a;
}
.bottom .options .register span:nth-child(1) {
color: #8c8c8c;
}
</style>
创作不易,源码非无偿提供,需要获取源码的私信博主