springboot考试答题系统


一.项目简单介绍

通过这么两个月以来的java学习,自己终于能够独立完成一个小型的项目了;

激动的同时,也暴露出自己不少的问题,在此有必要记录一下;

话不多说,直接进入主题!

此篇博客只做个记录,至于项目中遇到的问题,会另写一篇博客来总结;

先整体看一下效果吧:
基于前后端分离的springboot考试答题系统_springboot
登录后就显示一些题库,然后提交答案,之后自动批改选择题
基于前后端分离的springboot考试答题系统_springboot_02

此次写的是一个前后端分离的考试答题系统的小项目;

项目要求实现功能:

  • 登录
  • 展示题目
  • 保存题目
  • 自动批改考生选择题
  • 自动计算考生总成绩
  • 考生成绩排名

技术选型如下:



后端springboot,springMVC,mybatis,log4j,springboot定时任务
前端VUE
数据库mysql,druid连接池
项目管理和部署阿里云服务器,linux,maven,gitee码云

一下是maven中所有的依赖包及其对应额版本:

springboot使用的是2.4.0版本

  <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.18</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency><!--日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- 引入lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- gson格式转换 --><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version></dependency><!--引入热部署依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><!-- 引入实现分页功能的依赖--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version></dependency><!--thymeleaf模板引擎--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies>

依赖的介绍

  • lombok :可以简化类的书写,不用再自己写getter和setter方法
  • devtools:热部署,不用每次修改代码后重启项目,直接按ctrl+F9
  • gson:对前端传入的json数据进行转换

二.源代码

yml配置文件

spring:
  datasource:username: xxxpassword: xxxxdriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://xxxxx/exam?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf8type: com.alibaba.druid.pool.DruidDataSourceinitialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙filters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500


//配置这一部分,主要是使控制台打印SQL语句的一些信息logging:
  level:com:  jw:springbootexam:mapper: tracemybatis:
  configuration:map-underscore-to-camel-case: trueserver:
  port: 8080

//配置这一部分,主要是使控制台打印SQL语句的一些信息
logging:
level:
com:
jw:
springbootexam:
mapper: trace

config配置

@Configurationpublic class DruidConfig {@ConfigurationProperties(prefix = "spring.datasource")@Beanpublic DataSource druid(){return new DruidDataSource();}//配置Druid的监控//1.配置一个管理后台的servlet@Beanpublic ServletRegistrationBean stateViewServlet(){ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");Map<String,String> initParams = new HashMap<>();initParams.put("loginUsername","admin");initParams.put("loginPassword","123456");initParams.put("allow","");//默认就是允许所有都可访问bean.setInitParameters(initParams);return bean;}//2.配置一个web监控的filter@Bean//加入到容器汇中public FilterRegistrationBean webStatFileter(){FilterRegistrationBean bean = new FilterRegistrationBean();bean.setFilter(new WebStatFilter());Map<String,String> initParams = new HashMap<>();initParams.put("exclusions","*.js,*.css,/druid/*");bean.setInitParameters(initParams);bean.setUrlPatterns(Arrays.asList("/*"));return bean;}}

controller层

@Controller@CrossOrigin(origins="*")//解决跨域@Slf4j@RequestMapping("/user")public class TestController {@Autowiredprivate DisplayService displayService;/**
     * @Author YangJiaWen
     * @Description //校验考生的登录
     * @Date 12:04 2020/12/6
     * @Param [username, password]
     * @return java.util.Map<java.lang.String,java.lang.String>
     **/@PostMapping("/login")@ResponseBodypublic ResultVO checkUsernameAndPassword(@RequestParam("username") String username, @RequestParam("password") String password){StuLogin user = displayService.findPasswordByUsername(username);Map<String,String> map = new HashMap<>();if (user == null) {return ResultVOUtil.userNotExist();}else{if (password.equals(user.getPassword())){return ResultVOUtil.success(username);}}return ResultVOUtil.pwdNotTrue();}/**
     * @Author YangJiaWen
     * @Description //展示题目
     * @Date 12:03 2020/12/6
     * @Param []
     * @return java.util.Map<java.lang.String,java.lang.Object>
     **/@GetMapping("/exam")@ResponseBodypublic Map<String,Object> showAllSelect(){   Map<String,Object> map =new HashMap<>();   map.put("selectArray",displayService.showAllSelect());   map.put("subjectArray",displayService.showAllSubject());   return map;}/**
     * @Author YangJiaWen
     * @Description //保存考生的答案
     * @Date 12:04 2020/12/6
     * @Param [map]
     * @return void
     **/@PostMapping("/save")@ResponseBodypublic ResultVO saveAllAnswer(@RequestBody String json){Gson gson = new Gson();AllAnswer allAnswer = gson.fromJson(json, AllAnswer.class);System.out.println(allAnswer);int i = displayService.insertAllAnswer(allAnswer);if (i==2){return ResultVOUtil.success();}else{return ResultVOUtil.insertFail();}}}

mapper层

@Mapper@Repositorypublic interface selectMapper {//查询所有选择题@Select("select * from question_select")public List<QuestionSelect> findAllSelect();//查询所有客观题@Select("select * from question_program")public List<QuestionSubject> findAllSubject();//插入选择题答案@Insert("insert into answer_examinee_select(stuid,q1,q2,q3,q4,q5)" +"values(#{stuid},#{Q1},#{Q2},#{Q3},#{Q4},#{Q5})")public int insertChoiceAnswer(AnswerSelect answerSelect);//插入客观题答案@Insert("insert into answer_examinee_program(stuid,q6,q7,q8,q9,q10,q11,q12,q13,q14)" +"values(#{Stuid},#{Q6},#{Q7},#{Q8},#{Q9},#{Q10},#{Q11},#{Q12},#{Q13},#{Q14})")public int insertSubjectAnswer(AnswerSubject answerSubject);//查询选择题标准答案@Select("select * from answer_standard_select")public List<StandardSelectAns> findStandardSelectAns();//查询主观题标准答案@Select("select * from answer_standard_program")public List<StandardSubjectAns> findStandardSubjectAns();//查询考生答题情况@Select("select * from answer_examinee_select")public List<AnswerSelect> findAllSelectAns();//更新考生的选择题成绩@Update("update examinee_score set select_score = #{score} where stuid = #{stuId}")public int updateSelectScore(@Param("stuId")String stuId, @Param("score") int score);
     @Select("select * from stu_login where username=#{username}")public StuLogin selectByUsername(String username);}

model层

@Data@NoArgsConstructorpublic class AllAnswer{String password;AnswerSelect selectAns;AnswerSubject subjectAns;}@Data@NoArgsConstructorpublic class AnswerSelect {private String Stuid;private String Q1;private String Q2;private String Q3;private String Q4;private String Q5;}@Data@NoArgsConstructorpublic class AnswerSubject {private String Stuid;private String Q6;private String Q7;private String Q8;private String Q9;private String Q10;private String Q11;private String Q12;private String Q13;private String Q14;}@AllArgsConstructor@Datapublic class QuestionSelect {String Id;String Content;String optionA;String optionB;String optionC;String OptionD;}@Data@AllArgsConstructorpublic class QuestionSubject {String Id;String Content;}@Data@AllArgsConstructorpublic class StandardSelectAns {private String Id;private String Content;}@Data@AllArgsConstructorpublic class StandardSubjectAns { private String Id; private String Content;}@Data@AllArgsConstructorpublic class StuLogin {private Integer Id;private String Username;private String Password;}

service层

@Servicepublic class DisplayService {@Autowiredprivate selectMapper selectMapper;@Autowiredprivate UserMapper userMapper;public StuLogin findPasswordByUsername(String username){return userMapper.selectByUsername(username);}public List<QuestionSelect> showAllSelect(){return selectMapper.findAllSelect();}public List<QuestionSubject> showAllSubject(){return selectMapper.findAllSubject();}/**
     * @Author YangJiaWen
     * @Description //保存考生的所有答案
     * @Date 12:02 2020/12/6
     * @Param [map]
     * @return void
     **/public int insertAllAnswer(AllAnswer allAnswer){AnswerSelect selectAns = allAnswer.getSelectAns();AnswerSubject subjectAns = allAnswer.getSubjectAns();String password = allAnswer.getPassword();selectAns.setStuid(password);subjectAns.setStuid(password);int i = selectMapper.insertChoiceAnswer(selectAns);int i1 = selectMapper.insertSubjectAnswer(subjectAns);return i+i1;}/**
     * @Author YangJiaWen
     * @Description //自动批改考生的选择题
     * @Date 12:03 2020/12/6
     * @Param []
     * @return void
     **/@Scheduled(cron = "0 38 11 13 12 *")public void checkUserAns(){List<StandardSelectAns> standardSelectAns = selectMapper.findStandardSelectAns();List<AnswerSelect> allSelectAns = selectMapper.findAllSelectAns();List<String> answer=new LinkedList<>();for (AnswerSelect answerSelect : allSelectAns) {//考生选择题成绩int selectScore = 0;answer.add(answerSelect.getQ1());answer.add(answerSelect.getQ2());answer.add(answerSelect.getQ3());answer.add(answerSelect.getQ4());answer.add(answerSelect.getQ5());String stuId = answerSelect.getStuid();for (int i = 0; i < standardSelectAns.size(); i++) {String standardAns = standardSelectAns.get(i).getContent();String userAns = answer.get(i);if (standardAns.equals(userAns)){selectScore+=5;}}int i = selectMapper.updateSelectScore(stuId,selectScore);answer.clear();}}}

VO(返回给前端的类)

@Datapublic class ResultVO<T> {private String code;private String message;private T data;}public class ResultVOUtil {//成功public static ResultVO success(Object object){ResultVO resultVO = new ResultVO();resultVO.setCode("1");resultVO.setMessage("成功");resultVO.setData(object);return resultVO;}public static ResultVO success(){ return success(null);}public static ResultVO userNotExist(){ResultVO resultVO = new ResultVO();resultVO.setCode("0");resultVO.setMessage("用户名不存在");return resultVO;}public static ResultVO pwdNotTrue(){ResultVO resultVO = new ResultVO();resultVO.setCode("0");resultVO.setMessage("密码错误");return resultVO;}public static ResultVO insertFail(){ResultVO resultVO = new ResultVO();resultVO.setCode("0");resultVO.setMessage("保存失败");return resultVO;}}

这里只列举了部分代码,完整代码可以到我的码云(gitee)上去clone

SSH密钥:(git@gitee.com:yun_1002/yilingquestion.git).

此项目会持续更新!