java+vue+SpringBoot在线考试报名系统(程序+数据库+报告+部署教程+答辩指导)

#王者杯·14天创作挑战营·第5期#

源代码+数据库+LW文档(1万字以上)+开题报告+答辩稿ppt+部署教程+代码讲解+代码时间修改工具

技术实现

  1. 开发语言:后端:Java 前端:vue
  2. 框架:springboot
  3. 数据库:mysql

开发工具
JDK版本:JDK1.8
数据库:mysql 数据库工具:Navicat
开发软件:idea

主要角色及功能介绍
在线考试报名系统的功能主要分为前端学生根据自己的需求进行注册登录,浏览考试资讯,在线报名,在线模拟考试操作。后端系统管理员因职责的不同,分为普通管理员和超级管理员,管理员主要对注册学生,资讯数据,模拟试卷题目详细信息,试题管理,考试分值进行处理。
学生用例图如下所示。
在这里插入图片描述
图3-1 学生用例图
管理员用例图如下所示。
在这里插入图片描述
图3-2 管理员用例图
3.2.1前台用户功能
前端用户需求。
注册用户的功能如下:
注册账号:用户填写个人信息,并验证手机号码。
登录:根据账号密码进行登录操作。
在线报名数据:用户可以在线进行报名提交。
考试安排:用户可以根据考试时间进行考试安排。
维护个人信息:用户因个人信息的变更可以随时修改自己注册信息。
考试资讯:用户可以在系统浏览考试资讯信息。
考试成绩:用户可以查看自己在线考试成绩数据。
3.2.2后台管理员功能
管理员功能如下:
修改密码:管理员可以随时修改自己进入系统的登录密码,以保证系统的安全性。
试题信息进行处理:办理试卷考试成绩审核等。
考试报名管理:对学生提交的考试报名进行审核。
考试信息管理:对考试信息进行维护,添加、删除、修改信息。
考试列表管理:对试卷信息进行分类维护,添加、删除、修改信息。
资讯数据信息管理:发布、删除相关的资讯数据信息。
考试成绩管理:对学生在线考试试卷进行审核,考试成绩的发布。
在线考试报名系统总体分为前端用户模块和后端管理员模块。
两个模块表现上是分别独立存在,但是访问的数据库是一样的。每一个模块的功能都是根据先前完成的需求分析,并查阅相关资料后整理制作的。
综上所述,系统功能结构图如下图所示。
在这里插入图片描述
图4-2 系统功能结构图
数据库
根据前面的数据流程图,结合系统的功能模块设计,设计出符合系统的各信息实体。
系统ER图如下图所示。
在这里插入图片描述
图4-3 系统ER图
系统功能实现及截图
5.1注册模块的实现
用户在填写数据的时候必须与注册页面上的验证相匹配否则会注册失败,注册页面的表单验证是通过验证的,用户名的长度必须在6到18之间,邮箱必须带有@符号,密码和密码确认必须相同,你输入的密码,系统会根据你输入密码的强度给出指定的值,电话号码和身份证号码必须要求输入格式与生活相符合,当你前台验证通过的时候你点击注册,表单会将你输入的值通过name值传递给后台并保存到数据库中。
用户注册流程图如下图所示。
在这里插入图片描述
图5-1用户注册流程图
用户注册界面如下图所示。
在这里插入图片描述
图5-2用户注册界面
用户注册逻辑代码如下:
/**
* 注册
* @param user
* @return
*/
@PostMapping(“register”)
public Map<String, Object> signUp(@RequestBody User user) {
// 查询用户
Map<String, String> query = new HashMap<>();
query.put(“username”,user.getUsername());
List list = service.select(query, new HashMap<>()).getResultList();
if (list.size()>0){
return error(30000, “用户已存在”);
}
user.setUserId(null);
user.setPassword(service.encryption(user.getPassword()));
service.save(user);
return success(1);
}

/**
* 用户ID:[0,8388607]用户获取其他与用户相关的数据
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = “user_id”)
private Integer userId;

/**
 * 账户状态:[0,10](1可用|2异常|3已冻结|4已注销)
 */

@Basic
@Column(name = "state")
private Integer state;

/**
 * 所在用户组:[0,32767]决定用户身份和权限
 */

@Basic
@Column(name = "user_group")
private String userGroup;

/**
 * 上次登录时间:
 */

@Basic
@Column(name = "login_time")
private Timestamp loginTime;

/**
 * 手机号码:[0,11]用户的手机号码,用于找回密码时或登录时
 */

@Basic
@Column(name = "phone")
private String phone;

/**
 * 手机认证:[0,1](0未认证|1审核中|2已认证)
 */

@Basic
@Column(name = "phone_state")
private Integer phoneState;

/**
 * 用户名:[0,16]用户登录时所用的账户名称
 */

@Basic
@Column(name = "username")
private String username;

/**
 * 昵称:[0,16]
 */

@Basic
@Column(name = "nickname")
private String nickname;

/**
 * 密码:[0,32]用户登录所需的密码,由6-16位数字或英文组成
 */

@Basic
@Column(name = "password")
private String password;

/**
 * 邮箱:[0,64]用户的邮箱,用于找回密码时或登录时
 */

@Basic
@Column(name = "email")
private String email;

/**
 * 邮箱认证:[0,1](0未认证|1审核中|2已认证)
 */

@Basic
@Column(name = "email_state")
private Integer emailState;

/**
 * 头像地址:[0,255]
 */

@Basic
@Column(name = "avatar")
private String avatar;

/**
 * 创建时间:
 */

@Basic
@Column(name = "create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Timestamp createTime;

@Basic
@Transient
private String code;

}

5.2登录模块的实现
主要由两部分组成,登录前的登录界面以及登录后的用户功能界面。登录界面,要求用户输入用户名和密码,当用户名和密码其中一个输入为空时,给出提示“用户名,密码不能为空”。获取用户名和密码后到数据库中查找,如果用户名存在,以及对应的密码正确,则登录成功,否则登录失败。登录失败后给出提示,并把焦点停在文本框中。登录成功后将该次会话的全局变量username设置为用户名。登录成功后进入会员的功能模块,主要有会员基本信息修改,已经发布模拟考试信息管理,发布信息,和退出功能。退出功能是清除全局变量username的值,并跳回到首页。
登录流程图如下图所示。
在这里插入图片描述
图5-3登录流程图
用户登录界面如下图所示。
在这里插入图片描述
图5-4用户登录界面
用户登录的逻辑代码如下所示。
/**
* 登录
* @param data
* @param httpServletRequest
* @return
*/
@PostMapping(“login”)
public Map<String, Object> login(@RequestBody Map<String, String> data, HttpServletRequest httpServletRequest) {
log.info(“[执行登录接口]”);

    String username = data.get("username");
    String email = data.get("email");
    String phone = data.get("phone");
    String password = data.get("password");

    List resultList = null;
    Map<String, String> map = new HashMap<>();
    if(username != null && "".equals(username) == false){
        map.put("username", username);
        resultList = service.select(map, new HashMap<>()).getResultList();
    }
    else if(email != null && "".equals(email) == false){
        map.put("email", email);
        resultList = service.select(map, new HashMap<>()).getResultList();
    }
    else if(phone != null && "".equals(phone) == false){
        map.put("phone", phone);
        resultList = service.select(map, new HashMap<>()).getResultList();
    }else{
        return error(30000, "账号或密码不能为空");
    }
    if (resultList == null || password == null) {
        return error(30000, "账号或密码不能为空");
    }
    //判断是否有这个用户
    if (resultList.size()<=0){
        return error(30000,"用户不存在");
    }

    User byUsername = (User) resultList.get(0);


    Map<String, String> groupMap = new HashMap<>();
    groupMap.put("name",byUsername.getUserGroup());
    List groupList = userGroupService.select(groupMap, new HashMap<>()).getResultList();
    if (groupList.size()<1){
        return error(30000,"用户组不存在");
    }

    UserGroup userGroup = (UserGroup) groupList.get(0);

    //查询用户审核状态
    if (!StringUtils.isEmpty(userGroup.getSourceTable())){
        String sql = "select examine_state from "+ userGroup.getSourceTable() +" WHERE user_id = " + byUsername.getUserId();
        String res = String.valueOf(service.runCountSql(sql).getSingleResult());
        if (res==null){
            return error(30000,"用户不存在");
        }
        if (!res.equals("已通过")){
            return error(30000,"该用户审核未通过");
        }
    }

    //查询用户状态
    if (byUsername.getState()!=1){
        return error(30000,"用户非可用状态,不能登录");
    }

    String md5password = service.encryption(password);
    if (byUsername.getPassword().equals(md5password)) {
        // 存储Token到数据库
        AccessToken accessToken = new AccessToken();
        accessToken.setToken(UUID.randomUUID().toString().replaceAll("-", ""));
        accessToken.setUser_id(byUsername.getUserId());
        tokenService.save(accessToken);

        // 返回用户信息
        JSONObject user = JSONObject.parseObject(JSONObject.toJSONString(byUsername));
        user.put("token", accessToken.getToken());
        JSONObject ret = new JSONObject();
        ret.put("obj",user);
        return success(ret);
    } else {
        return error(30000, "账号或密码不正确");
    }

}

5.3用户资料修改模块的实现
用户登录/注册成功之后可以修改自己的基本信息。修改页面的表单中每一个input的name值都要与实体类中的参数相匹配,在用户点击修改页面的时候,如果改后用户名与数据库里面重复了,页面会提示该用户名已经存在了,否则通过Id来查询用户,并将用户的信息修改为表单提交的数据。
5.4考试信息推荐列表管理模块的实现
如果考试信息推荐列表数据的信息需要修改,管理员可以通过查询考试信息推荐列表数据的基本信息来查询考试信息推荐列表数据,查询考试信息推荐列表数据是通过ajax技术来进行查询的,需要传递考试信息推荐列表数据的标题、编号等参数然后在返回到该页面中,可以选中要修改或删除的那条信息,如果选中了超过一条数据,页面会挑一个窗口提醒只能选择一条数,如果没有选中数据会挑一个窗口题型必须选择一条数据。当选择确认修改的时候,后台会根据传过来的id到数据库查询,并将结果返回到修改页面中,可以在修改页面中修改刚刚选中的信息当点击确认的时候from表单会将修改的数据提交到后台并保存到数据库中,就是说如果提交的数据数据库中存在就修改,否则就保存。
考试信息推荐列表展示界面如下图所示。
在这里插入图片描述
图5-5考试信息推荐列表展示界面
考试信息推荐列表的逻辑代码如下:
@PostMapping(“/add”)
@Transactional
public Map<String, Object> add(HttpServletRequest request) throws IOException {
service.insert(service.readBody(request.getReader()));
return success(1);
}

@Transactional
public Map<String, Object> addMap(Map<String,Object> map){
    service.insert(map);
    return success(1);

}

public Map<String,Object> readBody(BufferedReader reader){
    BufferedReader br = null;
    StringBuilder sb = new StringBuilder("");
    try{
        br = reader;
        String str;
        while ((str = br.readLine()) != null){
            sb.append(str);
        }
        br.close();
        String json = sb.toString();
        return JSONObject.parseObject(json, Map.class);
    }catch (IOException e){
        e.printStackTrace();
    }finally{
        if (null != br){
            try{
                br.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    return null;

}

public void insert(Map<String,Object> body){
    StringBuffer sql = new StringBuffer("INSERT INTO ");
    sql.append("`").append(table).append("`").append(" (");
    for (Map.Entry<String,Object> entry:body.entrySet()){
        sql.append("`"+humpToLine(entry.getKey())+"`").append(",");
    }
    sql.deleteCharAt(sql.length()-1);
    sql.append(") VALUES (");
    for (Map.Entry<String,Object> entry:body.entrySet()){
        Object value = entry.getValue();
        if (value instanceof String){
            sql.append("'").append(entry.getValue()).append("'").append(",");
        }else {
            sql.append(entry.getValue()).append(",");
        }
    }
    sql.deleteCharAt(sql.length() - 1);
    sql.append(")");
    log.info("[{}] - 插入操作:{}",table,sql);
    Query query = runCountSql(sql.toString());
    query.executeUpdate();
}

5.5考试安排模块的实现
考试安排功能需要考虑高并发,特对考试这一共享数据增加锁机制。在乐观锁、悲观锁以及线程锁中,综合考虑性能效率和错误的可接受性选择了乐观锁机制。乐观锁的实现方式是使用版本标识来确定读到的数据与提交时的数据是否一致,提交后修改版本标识,不一致时可以采取丢弃和再次尝试的策略。在数据库考试表(对应考试实体)设计中增加了version字段,每次数据提交时(更改考试状态)会判断version是否匹配,若不匹配停止本次提交,若匹配则提交成功并增加version的值。
考试安排功能整体流程:用户浏览考试信息时,同时会显示考试的状态,系统会在其显示详细信息的页面时便会判断考试的状态,若考试状态为可考,则会显示答题的链接按钮。在用户点击答题按钮时,会先通过拦截器判断用户是否登录,若未登录,会跳转至登录页面,提示用户先登录,若为登录用户就会跳转至填写报名信息的页面,填写好报名信息之后,点击提交按钮,报名成功之后返回提示信息,告知用户答题成功。
考试安排流程图如下图所示。
在这里插入图片描述
图5-6考试安排流程图
考试安排界面如下图所示。
在这里插入图片描述
图5-7考试安排界面
考试安排界面逻辑代码如下:
@RequestMapping(value = {“/avg_group”, “/avg”})
public Map<String, Object> avg(HttpServletRequest request) {
Query count = service.avg(service.readQuery(request), service.readConfig(request));
return success(count.getResultList());
}
5.6考试报名管理模块的实现
根据需求,需要对考试报名管理进行添加、删除或修改详情信息。删除或修改考试报名管理时,系统根据考试报名管理的状态判定为可删除状态下,才会给出删除和修改链接,点击删除链接按钮时,请求到达后台,还会先查询考试报名管理状态再次做出判定能否删除。点击修改链接按钮时,会跳转到修改信息的页面,重新填写好数据后,数据提交到后台会对数据库中相应的记录做出修改。
添加考试报名管理时,会给出数据填写的页面,该页面根据填写好的考试报名管理编号同样会事先发送Ajax请求查询编号是否已存在,数据填写好之后提交到后台,会调用相关服务在数据库中插入记录。
考试报名管理流程图如下图所示。
在这里插入图片描述
图5-11考试报名管理流程图
考试报名添加页面设计效果如下图所示。
在这里插入图片描述
图5-12考试报名添加界面
考试报名管理页面效果如下图所示。
在这里插入图片描述
图5-13考试报名管理界面
考试报名管理界面关键代码如下:
@RestController
@RequestMapping(“auth”)
public class AuthController extends BaseController<Auth, AuthService> {
/**
* 服务对象
*/
@Autowired
public AuthController(AuthService service) {
setService(service);
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q_97095639

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值