SSH框架实现简单的在线考试系统
一、实验内容
1.1 实验介绍
在本次实验中,我们通过使用 spring4+struts2+hibernate5 的SSH框架来实现一个简单的在线考试系统。在前面的课程里,大家已经学习了如何使用较早版本的SSH框架来进行开发和整合项目,但其实在实际的企业开发中,较早版本的SSH框架由于代码维护性等各方面的原因,大多都已经被淘汰了,特别是 hibernate 框架的使用。自从 hibernate3.2 版本可以使用注解来做对象关系映射之后,以前使用 xml 文件来进行映射的方式就逐渐被淘汰了,SSH框架整合的配置文件也有了很大的不同。在接下来的实验中,我们将学习如何使用注解和配置文件的方式在数据库中自动建表以及以及框架整合的配置文件的注意事项。
1.2 实验知识点
SSH框架
Annotation注解
JSP
框架整合XML配置文件
1.3 实验环境
本次实验所用的实验环境要求如下;
JDK 1.8
hibernate5
spring4
struts2
eclipse
Tomcat7.0
1.4 项目源代码获取
wget [http://labfile.oss.aliyuncs.com/courses/852/TestOnline.zip]
二、项目文件结构
三、实验步骤
3.1 开发环境准备
3.1.1 选择Eclipse版本
由于在线环境中的 Eclipse 安装了两个版本,一个JDK版本为1.7,另一个支持JDK 1.8 版本。我们选择支持JDK 1.8 版本的 Eclipse:
选择eclipse
双击打开后,就可以创建项目了。
3.1.2 创建实验项目
接下来我们要创建我们的实验项目了。首先,在项目空白区域点击右键–>new–>Dynamic Web Project,选定并确认后,会要求我们输入新建项目的名称(本次课程我们的项目名为TestOnlinenew),
注意,输入完项目的名称后不要立即点击finish,应该连续两次点击next后,将自动生成web.xml文件的选项勾上,最后finish。
现在空的项目创建好了,接下来就是调整jdk的版本以及Tomcat服务器的配置。首先将jdk的版本设置为JDK1.8,步骤是:依次点击eclipse上方的Window–>Preferences,在左上角的搜索栏中输入jre,找到Installed JREs下的 Execution Environments,将他打开后选择JavaSE 1.8 ,并且将右方的JREs打上勾,点击OK。
3.1.3 导入项目所需的Jar包
通过下面的命令下载项目所需要的Jar包:
下载完成后使用命令解压压缩包:
unzip SSH.zip
解压完成后,打开主文件夹,找到我们刚才解压的存放Jar包的文件夹,然后将里面的所以Jar包复制到我们刚才创建的项目的WEB-INF的lib目录下。
复制完成后,还需要在项目中配置,依次右键点击项目名–>Build Path–>Configure Build Path,进入到如下页面。
在Libreries中选择Add JARs,然后选择TestOnline–>WebContent–>lib,选中全部Jar包,最后在Order and Export窗口下选中全部包,点击OK,退出。
3.1.4 数据库开发准备
虽然hibernate框架能为我们在开发时省却很多数据库工作,但是仍然需要做一些必要的数据库准备工作——创建项目对应的数据库。在这里我们只需要创建一个空的数据库就行了,其他的建表等工作将由hibernate框架为我们完成。
首先使用命令启动数据库服务。
sudo service mysql start
然后使用用户名和密码进入mysql数据库。
mysql -u root
我们在线环境的mysql数据库用户名为root,密码默认为空。
进入数据库后,可以使用
show databases;
查看当前所有数据库。我们数据库准备的最后一步就是创建一个新的数据库,起名为test,命令如下:
create database test;
准备工作完成后,接下来就是具体代码的实现了。
3.2 配置文件
由于使用注解来处理数据库的映射关系,那么相比较于以前,我们可以省去全部xxx.hbm.xml格式的xml文件以及hibernate.cfg.xml文件,将其交给Spring容器来控制。
3.2.1 web.xml的配置
在web.xml中,我们配置的具体信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>TestOnline</display-name>
<!-- 加载spring相关的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value>
</context-param>
<!-- 启用spring监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<!-- 配置Struts2 -->
<filter-name>TestOnline</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TestOnline</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 项目欢迎页面 -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
对于web.xml来说,和以前的配置没有什么大的区别。改变最大的配置文件是Spring的配置文件——applicationContext.xml。
3.2.2 applicationContext.xml
在项目的src目录下新建一个xml文件,名为applicationContext.xml,里面的具体配置信息如下:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<!-- 引入properties文件 -->
<context:property-placeholder location="classpath*:/db.properties" />
<context:annotation-config />
<!-- 对指定的包进行组件扫描 -->
<context:component-scan base-package="com.testonline" />
<!-- 使用annotation 自动注册bean, 并保证@Required、@Autowired的属性被注入 -->
<context:component-scan base-package="com.testonline.hibernate,com.testonline.action">
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
<!-- 定义数据库连接池数据源bean -->
<context:annotation-config />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.driverName}"/>
<property name="url" value="${hibernate.url}"/>
<property name="username" value="${hibernate.username}"/>
<property name="password" value="${hibernate.password}"/>
</bean>
<!-- 定义Hibernate Session工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan" value="com.testonline.hibernate" /><!-- 如果多个,用“,”分隔 -->
</bean>
<!-- 定义事务 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
</beans>
在applicationContext.xml中,我们将以前的hibernate.cfg.xml整合在了这里面。我们引入了一个数据库的properties文件,它的作用是为了更加灵活的进行数据库的连接,而且在配置文件中不会显示数据库的连接信息。在hibernate5中,它将生成sessionfactory交给了spring来实现。
3.2.3 数据库读写文件db.properties文件
右键点击项目的src目录,new–>file,确认后输入db.properties,在这里面配置书库库读写文件。其具体信息如下:
hibernate.driverName=com.mysql.jdbc.Driver
hibernate.url=jdbc:mysql://localhost:3306/test
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.username=root
hibernate.password=
hibernate.maxIdle=255
hibernate.minIdle=2
hibernate.maxWait=120000
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
db.properties文件将数据库信息很的封装了起来,提高了安全性。
3.2.4 struts.xml
struts2的配置文件struts.xml的配置方式和以前相同,在这里就不过多的叙述了,本次课程的struts.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="Action" namespace="/" extends="struts-default">
<action name="login" method="login" class="LoginAction">
<result name="success">/choose_course.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="choose_course" method="choose" class="choose">
<result name="success">/test.jsp</result>
<result name="error">/error.jsp</result>
<result name="error">/over.jsp</result>
</action>
<action name="Checkanswer" method="checkanswer" class="choose">
<result name="success">/right.jsp</result>
<result name="error">/Wrong.jsp</result>
</action>
</package>
</struts>
3.3 实体类
本次课程中涉及到的实体类有Student学生类、Course课程类、Test试题类三个,其中Course和Test是一对多的关系。这些实体类全部放在src目录下的com.testonline.hibernate包。
3.3.1 Student实体类
Student实体类对应了student这个表,他有三个字段,用来存放学生信息。Student实体类的具体代码和注释请看下面:
package com.testonline.hibernate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/*
* @Entiy标识这是一个实体类
* @Table表示在数据库中创建的表的名字
*
*/
@Entity
@Table(name="student")
public class Student {
private int Id;
private String name;
private String password;
//@Id表示该列是主键
//@GeneratedValue表示主键生成策略
//@Column是为列取别名,可以没有
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id")
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3.3.2 Course实体类
Course实体类用于存放课程信息,只有两个字段,Course实体类与后面的Test实体类有一对多的映射关系。在Course实体类中我们用@OneToMany来注解。具体如下:
package com.testonline.hibernate;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="course")
public class Course {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="ID")
private int courseID;
private String course;
//@OneToMany映射关系
//CascadeType为级联属性
//@JoinColum为对应的多的一方的列
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="course_ID")
private Set<Test> t = new HashSet<>();
public Set<Test> getT() {
return t;
}
public void setT(Set<Test> t) {
this.t = t;
}
public int getCourseID() {
return courseID;
}
public void setCourseID(int courseID) {
this.courseID = courseID;
}
public String getCourse() {
return course;
}
public void setC(String course) {
this.course = course;
}
}
在这里要注意,如果在多个字段上都有注解,那么他们注解的位置应该一致,都是在属性定义前或者都在get、set方法前,否则会报错。
3.3.3 Test实体类
Test实体类映射test试题表,用于存放试题的信息,在与Course的关系中是多的一方,其具体的信息如下:
package com.testonline.hibernate;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="test")
public class Test {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "testID")
private int testID;
private String title;
private String answer;
private String A;
private String B;
private String C;
private String D;
//@Basic是抓取策略
//JoinColum要与Course中对应
@ManyToOne
@JoinColumn(name="course_ID")
@Basic(fetch=FetchType.LAZY)
private Course course;
public Course getCourse() {
return course;
}
public void setCourseID(Course course) {
this.course= course;
}
public int getTestID() {
return testID;
}
public void setTestID(int testID) {
this.testID = testID;
}
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
public String getB() {
return B;
}
public void setB(String b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
public String getD() {
return D;
}
public void setD(String d) {
D = d;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setCourse(Course course) {
this.course = course;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
3.4 JSP页面
本次课程总共有五个主要的JSP页面,他们都放在WebContent目录下,除去错误页面error.jsp和结束页面over.jsp以外(这两个页面都只是提示用,页面只输出一句话,在这里代码就省略了),还有用于学生登录的页面login.jsp、用于选择课程的页面choose_course.jsp以及用于显示试题的页面test.jsp。
在登录页面中,要求登录者需要验证登录名和密码。login.jsp代码如下:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
</head>
<body>
<form action="login" method="post">
<table border="1" >
<tr>
<td>name:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
</tr>
</table>
<input type="submit" value="login">
<input type="reset" value="reset">
</form>
</body>
</html>
在课程选择页面choose_course.jsp中,我们要求用户选择现有课程的一门进行考试:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Course</title>
</head>
<body>
<form name="choose" action="choose_course" method="post">
<table border="1" width="150" height="160">
<tr>
<td>java</td>
<td><input type="radio" name="course" value="Java">
<tr>
<td>C</td>
<td><input type="radio" name="course" value="C">
<tr>
<td>HTML5</td>
<td><input type="radio" name="course" value="HTML5">
</table>
<input type="submit" value="Sure">
</form>
</body>
</html>
在考试页面test.jsp提供了显示试题和用户作答的表格:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h3><s:property value="#session.list.TITLE" /></h3>
<form action="Checkanswer" method="post">
<table border="1" width="400" height="400">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>Your Answer</th>
</tr>
<tbody>
<tr>
<td><s:property value="#session.list.A" /></td>
<td><s:property value="#session.list.B" /></td>
<td><s:property value="#session.list.C" /></td>
<td><s:property value="#session.list.D" /></td>
<td>
<input type="radio" name="answer" value="A">A
<input type="radio" name="answer" value="B">B
<input type="radio" name="answer" value="C">C
<input type="radio" name="answer" value="D">D
</td>
</tr>
</tbody>
</table>
<input type="submit" value="sure">
</form>
</body>
</html>
选择答案后,会检答案的额正确性,答案正确提示right并点击next选择下一题,答案错误则在提示wrong后,给出正确答案,并提供next下一题的连接。如果题目全部完成,则提示Over结束。 over.jsp 是结束页面,由于只有简短的一句提示语,所以在文档中就省略了。
正确答案的right.jsp页面代码:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
You are right !!!
<s:url var="next_page" value="choose_course.action">
<s:param name="pageNow" >
<s:property value="#session.pageNow" />
</s:param>
<s:param name="course" >
<s:property value="#session.course"/>
</s:param>
</s:url>
<s:a href="%{next_page}">Next</s:a>
</body>
</html>
错误答案的Wrong.jsp页面代码:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h3>You are Wrong.</h3>
<tr>
The answer is <s:property value="#session.answer" />
</tr>
<s:url var="next_page" value="choose_course.action">
<s:param name="pageNow" >
<s:property value="#session.pageNow" />
</s:param>
<s:param name="course" >
<s:property value="#session.course"/>
</s:param>
</s:url>
<s:a href="%{next_page}">Next</s:a>
</body>
</html>
3.4 Action的编写
所有的Action都位于com.testonline.action包中。包含LoginAction和ChooseCourseAction,一个用于登录验证,一个用于选择课程和试题。
3.4.1 LoginAction
LoginAction用于验证学生姓名和密码,验证成功返回success,跳转到课程选择,失败则返回error,跳转到失败提示页面。LoginAction的具体代码package com.testonline.action;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.testonline.hibernate.Student;
import com.testonline.service.*;
/*
*@Controller定义控制器
*@Scope 标识作用域
*@Resource 注入service
*
*/
@Controller(“LoginAction”)
@Scope(“prototype”)
public class LoginAction {
@Resource(name=”service”)
//设值注入
private service service;
public service getService() {
return service;
}
public void setService(service service) {
this.service = service;
}
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
public String login(){
//接收action传过来的信息
String name = request.getParameter("name");
String pwd = request.getParameter("password");
try {
//判断用户名和密码是否为空
if(name!=null && pwd!=null && !name.equals("") && !pwd.equals("")){
//根据用户名查找student的信息
Student stu = this.service.checkname(name);
if(stu!=null){
//用户名和密码对应验证
if(name.equals(stu.getName()) && pwd.equals(stu.getPassword())){
return "success";
} else return "error";
} else return "error";
} else return "error";
} catch (Exception e) {
System.out.println(e);
return "error";
}
}
}
在LoginAction中只是调用了service层的相关方法来获取数据,至于servic层是怎样得到数据的,action并不关心。
3.4.2 ChooseCourseAction
ChooseCourseAction用于根据用户选择的course来选出符合course条件的所有的试题,并将试题存放入session来返还给jsp页面。试题的切换采用分页的原理,具体在daoImpl中实现。具体代码如下:
package com.testonline.action;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionContext;
import com.testonline.hibernate.Test;
import com.testonline.service.*;
/*
* 前面的注解和注入基本与LoginAction相同
*
*/
@Controller("choose")
@Scope("prototype")
public class ChooseCourseAction {
@Resource(name="service")
private service service;
private int pageNow=0; //初始页为第一页
private int pageSize=1; //每页数据为1条,可调节
public service getService() {
return service;
}
public void setService(service service) {
this.service = service;
}
public int getPageNow() {
return pageNow;
}
public void setPageNow(int pageNow) {
this.pageNow = pageNow;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
Map<String, Object> session4 = ActionContext.getContext().getSession();
String ret = null;
/*
* 课程选择方法
* 选择课程后跳转到对应的题目
*/
public String choose(){
Map<String, Object> session1 = ActionContext.getContext().getSession();//存储结果集
Map<String, Object> session2 = ActionContext.getContext().getSession();//存储testID,用于检查正确答案
Map<String, Object> session3 = ActionContext.getContext().getSession();//存储课程,保证课程不会改变
Map<String, Object> session4 = ActionContext.getContext().getSession();//保存当前题目的页数
//接收数据
String co = request.getParameter("course");
String page = request.getParameter("pageNow");
if(page == null){
pageNow = 0;
}else{
pageNow = Integer.parseInt(page);
}
List<Test> list = new ArrayList<Test>();
try {
//根据课程查找试题
list = this.service.findtest(co,pageNow,pageSize);
//如果查询结果是null,则意味着题目以及做完了
if (list == null) {
ret = "over";
}else{
session4.put("pageNow", pageNow+1);
//将试题放入session,便于前台取用显示
session1.put("list", list.get(0));
session2.put("testID",list.get(0).getTestID());
session3.put("course", co);
ret = "success";
}
} catch (Exception e) {
System.out.println(e);
ret = "error";
}
return ret;
}
/*
* 检查答案,正确返回success
* 错误返回error并将正确答案显示
*
*/
public String checkanswer(){
Map<String, Object> session1 = ActionContext.getContext().getSession();
String ret = "error";
//得到我们在上面取出 的testID
int s = (int) session.getAttribute("testID");
try {
String answer = request.getParameter("answer");//得到用户选择的答案
//取出正确答案
Test t = this.service.checkanswer(s);
session1.put("answer", t.getAnswer());
//验证
if (answer!=null) {
if (t.getAnswer().equals(answer)) {
ret= "success";
}
}else{
ret= "error";
}
} catch (Exception e) {
System.out.println(e);
ret= "error";
}
return ret;
}
}
3.5 service服务层
在service层中,主要包含了service接口和他的实现类。service接口定义了我们需要让service层完成的事,供外部访问,而它的实现类重写了这些方法。
service接口:
package com.testonline.service;
import java.util.List;
import com.testonline.hibernate.Student;
import com.testonline.hibernate.Test;
public interface service {
//LoginAction调用方法,用于查找student信息
Student checkname(String name);
//ChooseCourseAction调用方法,用于查找试题信息
List<Test> findtest(String course, int pageNow, int pageSize);
//查找正确答案
Test checkanswer(int s);
}
接口实现类serviceImpl:
package com.testonline.service;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.testonline.dao.dao;
import com.testonline.hibernate.Student;
import com.testonline.hibernate.Test;
/*
* @service标注业务层组件
* @Transactional标注事务管理
*
*/
@Service("service")
@Transactional(readOnly=false)
public class serviceImpl implements service {
@Resource(name="dao")
private dao dao;
//设值注入
public dao getDao() {
return dao;
}
public void setDao(dao dao) {
this.dao = dao;
}
//重写方法
@Override
public Student checkname(String name) {
Student str = this.dao.checkname(name);
return str;
}
//重写方法
@Override
public List<Test> findtest(String course,int pageNow, int pageSize) {
List<Test> list = this.dao.findtest(course,pageNow,pageSize);
return list;
}
@Override
public Test checkanswer(int s) {
Test t = this.dao.checkanswer(s);
return t;
}
}
3.6 DAO层
在dao层中包含了提供给外部访问的接口dao和接口实现类daoImpl。在daoImpl中是两个action的底层的数据处理。接口dao定义了两个action需要调用的方法:
package com.testonline.dao;
import java.util.List;
import com.testonline.hibernate.Student;
import com.testonline.hibernate.Test;
public interface dao{
Student checkname(String name);//查找学生信息
List<Test> findtest(String course, int pageNow, int pageSize);//查找试题
Test checkanswer(int s);//查找答案
}
接口实现类daoImpl:
package com.testonline.dao;
/*
* @Repository表示持久层
* @Autowired在配置文件中配置的生成sessionFactory的注解
*
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.opensymphony.xwork2.ActionContext;
import com.testonline.hibernate.Student;
import com.testonline.hibernate.Test;
@Repository("dao")
@Transactional(readOnly=false)
public class daoImpl implements dao{
@Autowired
private SessionFactory sessionFactory;
@SuppressWarnings("deprecation")
@Override
public Student checkname(String name) {
List<Student> stu = new ArrayList<Student>();
Session session = sessionFactory.getCurrentSession();
@SuppressWarnings("unchecked")
//执行hql语句并将结果转化成Student类型的list集合
Query<Student> query = session.createQuery("from Student where name=?").setParameter(0, name);
stu = query.list();
System.out.println(stu);
//返回符合条件的Student的信息
if(stu.size()!=0){
return stu.get(0);
} else{
return null;
}
}
@SuppressWarnings("deprecation")
@Override
public List<Test> findtest(String course,int pageNow, int pageSize) {
Map session1 = ActionContext.getContext().getSession();
Session session = sessionFactory.getCurrentSession();
//执行原生的SQL语句,数据库分页查询
Query query = session.createSQLQuery("select t.testID,t.title,t.A,t.B,t.C,t.D from test as t,"
+ "course as c where c.course='"+course+"' and c.ID=t.course_ID limit "+pageNow+","+pageSize+"");
//将结果集注入到实体类Test的Bean中
query.setResultTransformer(Transformers.aliasToBean(Test.class));
@SuppressWarnings("unchecked")
//类型转换
List<Test> list =(List<Test>) query.list();
System.out.println("pageNow3="+pageNow);
System.out.println("pageNow4="+pageNow);
System.out.println(list.get(0).getA());
return list;
}
@SuppressWarnings("deprecation")
@Override
public Test checkanswer(int s) {
List<Test> t = new ArrayList<Test>();
Session session = sessionFactory.getCurrentSession();
@SuppressWarnings("unchecked")
//执行hql语句并将结果转化成Test类型的list集合
Query<Test> query = session.createSQLQuery("select answer from test where testID=? ").setParameter(0, s);
query.setResultTransformer(Transformers.aliasToBean(Test.class));
t = query.list();
//返回符合条件的Test的信息
if(t.size()!=0){
return t.get(0);
} else{
return null;
}
}
}
在查找试题时,是多表关联的数据库分页查询。在这里因为我们只需要查找的是试题类容,所以只对应了Test表的字段,因此只需要将结果集转化为Test类型就行了。如果多表关联查询的是两个以上的表中的字段,那么比较简单的做法是建一个中间的VO实体类,VO类包含所有需要查找的字段,然后做类型转换的操作。Mysql的数据库分页可以使用limit语句。limit语句有两个参数,limit m ,n,其中m为从哪条记录开始读取,n表示每次读取几条记录。
3.7 运行测试
代码的编写全部完成了,现在就让我们来测试一下吧。
3.7.1 数据库测试
如果我们要测试数据库是否自动建表,我们需要先将项目部署到Tomcat服务器下,然后启动服务器。或者直接右击项目名,选择Run As–>Run On Server,然后Eclipse会自动识别Tomcat 7.0 服务器,点击finish,静静的等待服务器启动。在启动的过程中可能会遇到启动的时间不足的问题,你只需要在下方的Server栏中双击Tomcat 7.0 服务器。
然后点击右上角的Timeouts按钮,将启动时间调整一下,保存退出就行了:
启动服务器后,我们就可以进入test数据库看看它是否自动建表。打开Xfce终端,输入:
show databases;
显示数据库,然后选择我们创建的数据库test
use test;
然后我们查看test数据库中的表:
show tables;
如果出现了我们创建实体类时所映射的表,那么说明通过注解建表成功。如下图:
在结果中出现了一张名为,如果我们要进行接下来的测试的话,那么我们还需要往数据库中添加数据。在Xfce终端进入test数据库后,连续使用插入命令
Insert into 表名 VALUE (‘值1’,’值2’,…);
可以在数据库中对应的表中添加记录。比如在学生表中添加记录(主键生成策略是自动增长,所以也可以将主键位置的值设置为空,但不能少了主键列):
Insert into student VALUE (‘1’,’hh’,’123’);
然后依次往course表和test表中插入数据:
course表:
INSERT INTO
courseVALUES (‘1’, ‘C’);
INSERT INTOcourseVALUES (‘2’, ‘java’);
INSERT INTOcourseVALUES (‘3’, ‘HTML5’);
test表:
INSERT INTO
testVALUES (‘1’, ‘#’, ‘@’, ‘!’, ‘$’,’A’, ‘What does
the C language preprocessing command start with?’, 1);INSERT INTO
testVALUES (‘2’, ‘print’, ‘int’, ‘var’, ‘out’,
‘A’,’What keywords does C language output use?’,’1’);INSERT INTO
testVALUES (‘3’, ‘Conllection’, ‘Map’, ‘HashMap’, ‘No’,
‘A’, ‘The interface to the Map collection is?’, ‘2’);INSERT INTO
testVALUES (‘4’, ‘Polymorphism’, ’ inheritance’,
‘packaging’, ‘AOP’, ‘D’,’Which of the following is not the three major
feature of Java?’, ‘2’);INSERT INTO
testVALUES (‘5’, ‘HTML5 is the fifth revision of the
HTML standard’ ,’HTML5 is object oriented programming’, ‘HTML5 is
process oriented programming’, ‘NO HTML5’,’A’,’What is HTML5?’, ‘3’);
添加完成后course表如下图:
test表:
3.7.2 程序运行结果
在启动了服务器的前提下,我们直接打开环境自带的Firfox浏览器,在地址栏输入
就可以进入登录页面:
输入对应的学生姓名和密码(刚才在数据中插入的记录),如果正确就会跳转的课程选择页面,错误会跳转到错误页面。课程选择页面:
课程选择完成后,点击sure按钮,会根据不同的课程显示不同的题目:
答案正确页面:
错答页面:
四、实验总结
在本次试验中,我们利用SSH框架实现了简单的在线考试系统,通过使用注解映射取代了映射文件,并成功的实现了自动建表和一对多的映射关系。
本文介绍使用SSH框架(Spring4+Struts2+Hibernate5)实现的简单在线考试系统,涵盖开发环境搭建、代码实现及数据库自动建表等内容。
6531

被折叠的 条评论
为什么被折叠?



