在线考试系统
本系统实现了对试题的怎删改查,以及随机生成试卷,考生答题等功能
用时一周,只实现了基本功能,后期还将继续完善
项目结构
登录注册
使用了shiro安全框架,对本系统进行权限管理下面来看一看具体的代码
UserRealm
public class UserRealm extends AuthorizingRealm {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String)principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.findRoles(username));
authorizationInfo.setStringPermissions(userService.findPermissions(username));
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String)token.getPrincipal();
User user = userService.findByUsername(username);
if(user == null) {
throw new UnknownAccountException();//没找到帐号
}
if(Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); //帐号锁定
}
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
@Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
}
@Override
public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
super.clearCachedAuthenticationInfo(principals);
}
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
public void clearAllCachedAuthorizationInfo() {
getAuthorizationCache().clear();
}
public void clearAllCachedAuthenticationInfo() {
getAuthenticationCache().clear();
}
public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
}
}
在shiro.xml中配置权限
这个框架还是蛮好用的,它会自动记录用户登录信息,以及判断用户登录状态,方便了我们对系统的权限控制。
同时前端也可以加入shiro标签,用户处于登录或非登录状态显示内容有所不同
如下
<shiro:guest>
<h3>欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp"><button class="btn btn-primary">点击登录</button> </a></h3><br/>
</shiro:guest>
<shiro:user>
<h3>欢迎[<shiro:principal/>]登录,<a href="${pageContext.request.contextPath}/logout"><button class="btn btn-danger">点击退出</button> </a></h3> <br/>
<h3><a href="/toMyPage"><button class="btn btn-primary">点击前往</button></a></h3>
</shiro:user>
其中遇到了一个问题,在使用shiro框架的缓存功能时,会莫名其妙的生成多个缓存文件,报错只告诉我配置错误。
解决方法如下
建议大家使用2.4.8版本
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.8</version>
</dependency>
添加试题功能
效果图
我在这个最初的功能上卡了一段时间,因为我不仅要将试题放到数据库中,还需要将它出成试卷,不能一股脑的将试题内容放进去。
其他人的项目中有一种方法,将试题转换成xml语言放入数据库,调用时,再转化成html语言,对我来说难度太高。于是我就想将整道试题的html页面的html代码存入数据库,但是考虑到出题页面和做题页面形式不同会比较麻烦,所以就取了个比较low的方法。
将试题题目,选项,答案分别插入数据库,如果是简答题选项就为空,出试卷时就分别遍历一遍。下面是controller中具体实现的代码
public String addQuestion(TQuestion question, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String loginName = (String) SecurityUtils.getSubject().getPrincipal();
Message message=new Message();
question.setCreatTime(new Date());
question.setCreator(loginName);
try{
questionService.addQuestion(question);
request.setAttribute("message","添加成功");
}catch (Exception e){
request.setAttribute("message",e.getClass().getName());
// message.setResult("error");
// message.setMessageInfo(e.getClass().getName());
e.printStackTrace();
}
return "admin/questionAdd";
}
@RequestMapping(value = "/admin/questionList", method = RequestMethod.GET)
public String questionListPage(@RequestParam(defaultValue = "1",required = true,value = "pageNo")Integer pageNo, Model model){
Integer pageSize=10;
PageHelper.startPage(pageNo,pageSize);
List<TQuestion> questionList=questionService.getQuestionList();
PageInfo<TQuestion> pageInfo=new PageInfo<>(questionList);
model.addAttribute("questionList",questionList);
return "admin/questionList";
}
随机生成试卷
输入每个题型的试题数,从数据库中查询相应数量的试题生成试卷
以下是controller层的代码
public String addPaper(@RequestParam int selectNum, @RequestParam int multipleNum,
@RequestParam int descNum, TPaper paper, Model model, HttpSession session){
Map map=new HashMap();
List<TQuestion> selectList = null;
List<TQuestion> multipleList = null;
List<TQuestion> descList = null;
List<TQuestion> paperList = new ArrayList<TQuestion>();
if(selectNum>0){//选择题
map.put("num", selectNum);
map.put("typeId", 1);
selectList = questionService.creatPaper(map);
paperList.addAll(selectList);
}
if(multipleNum>0){//判断题
map.put("num", multipleNum);
map.put("typeId", 4);
multipleList = questionService.creatPaper(map);
paperList.addAll(multipleList);
}
if(descNum > 0 ){//描述题
map.put("num", descNum);
map.put("typeId", 5);
descList = questionService.creatPaper(map);
paperList.addAll(descList);
}
String quesId = "";
for(TQuestion ques : paperList){
quesId+=ques.getId()+",";
}
if(!quesId.isEmpty()){
quesId = removeLast(quesId);
}
paper.setQuestionId(quesId);
paper.setPaperstate("0");
paperService.insert(paper);
return "redirect:/teacher/toPaperList";
}
学生答卷
通过之前插入的试题id依次遍历,查询试题表中的内容,根据其实体类型分别传向前端
以下
public String qryPaperDetail(String id, Model model, HttpSession session, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
Map map = new HashMap();
map.put("id", id);
TPaper paper = paperService.getPaperDetail(map);
String []ids = paper.getQuestionId().split(",");
List<TQuestion> selList = new ArrayList<TQuestion>();
List<TQuestion> inpList = new ArrayList<TQuestion>();
List<TQuestion> desList = new ArrayList<TQuestion>();
for(int i = 0;i<ids.length;i++){
int li=Integer.parseInt(ids[i]);
TQuestion question = questionService.findQuestionById(li);
if(question.getTypeId()==1){//单选
selList.add(question);
}
if(question.getTypeId()==2){//填空
inpList.add(question);
}
if(question.getTypeId()==4){//简答题
desList.add(question);
}
}
if(selList.size()>0){
model.addAttribute("selectQ", "单项选择题(每题5分)");
model.addAttribute("selList", selList);
}
if(inpList.size()>0){
model.addAttribute("inpQ", "多选题(每题5分)");
model.addAttribute("inpList", inpList);
}
if(desList.size()>0){
model.addAttribute("desQ", "简答题(每题5分)");
model.addAttribute("desList", desList);
}
model.addAttribute("paper", paper);
return "/student/paper-detail";
}
jsp页面将不同页面遍历出来
<div class="container">
<!-- 试卷名称 -->
<h2 class="bars" align="center"><font color="blue">${paper.papername }</font></h2>
<div class="input-group">
<h4 class="bars" align="left"><font color="blue">${selectQ}</font></h4>
</div>
<c:forEach items="${selList}" var="selType">
<p><h4 class="bars" align="left">${selType.name }</h4></p>
<div class="input-group">
<input name="${selType.id }" type="radio" value="A" checked="checked"/><font size="4">${selType.optiona }</font></br>
<input name="${selType.id }" type="radio" value="B"/><font size="4">${selType.optionb }</font></br>
<input name="${selType.id}" type="radio" value="C"/><font size="4">${selType.optionc}</font></br>
<input name="${selType.id }" type="radio" value="D"/><font size="4">${selType.optiond }</font></br>
<%-- <p><h4 class="bars"><font color="blue">我的答案:${errorBook.userAnswer } </font></h4></p>
<p><h4 class="bars">标准答案:${errorBook.question.answer }( ${errorBook.question.answerDetail })</h4></p>
<p><h4 class="bars"><font color="red">解析:${errorBook.question.remark }</font></h4></p> --%>
</div>
总结
其实和其他人的项目大同小异,而且因为是紧迫只完成了基本功能。
还是要注意Mybatis映射,我会经常在这上面出错。
感觉自己在前期设计项目时做的还算不错,在开始编写前就把项目的每个功能模块化。
但是我有些急功近利,刚开始一股脑的把后台接口都写完,然后运行后就会发现一大堆的报错,改错的时间其实比编码时间要长得的多。做什么事还是不能太急于求成,一步一步脚踏实地得来。
就这样吧~