面向对象程序设计(java)
基于有状态的课堂点名系统
一、项目简介
功能描述
本项目为可以记录学生回答情况的web点名系统。
参考博客地址
个人负责任务:
整个项目的构思与编程。
代码gitee地址
二、功能架构图
个人任务简述
1.完成的任务与功能:
序号 | 完成功能与任务 | 描述 |
---|---|---|
1 | 随机点名功能 | 使用Random函数给出随机数及非指定查询,实现了对学生的随机点名,避免指定学生被删除后查找不到数据的错误。 |
2 | 面向对象设计 | 使用了面向对象技术设计系统。 |
3 | 登录功能 | Web加入登陆验证,使系统更加安全。 |
4 | 优势点名功能 | 在n位同学没能正确回答问题后,在答对率最高的5名同学中随机选择一位进行下一次作答,并且在后台提供了n值的设置页面。 |
5 | 输入提示功能 | 使用javascript在用户使用表格注册方式时自动纠正答对次数与被叫次数的大小关系,并且自动计算答对率 |
6 | 清空功能 | 在用户连续删除三个同学后给出使用清空按钮的提示,一键清空学生的信息。 |
7 | 文件注册功能 | 可以允许用户使用txt文件批量注册学生信息。 |
8 | 数据库读写编码部分 | 使用了DAO模式。 |
9 | 数据库设计 | 采用MySQL数据库。表设计符合第三范式。 |
2.Git提交记录截图:
四、本人负责功能详解
1.*面向对象设计
2.*随机点名功能
通过Random函数给出随机值,通过SQL语句在数据库中找出特定同学,但如果有一位学生被删除后,SQL数据库中会找不到这个数据导致返回为空,导致报错或返回到用户界面为空。最终通过修改查条件,使在SQL数据库中并不按照特定序号查询,而是查找大于等于或小于等于随机编号的一条数据。
else{
if( (student = sdao.callUp(hbid))== null){
student = sdao.callUpb(hbid);
}
}
Dao部分
public Students callUp(Integer cbid) {
String sql = "select * from students where bid >=? limit 1";
PreparedStatement qps = sUtil.createStatement(sql);
ResultSet snrs ;
Students student = null;
try {
qps.setInt(1,cbid);
snrs = qps.executeQuery();
while(snrs.next()) {
Integer bid = snrs.getInt("bid");
String sid = snrs.getString("sid");
String sname = snrs.getString("sname");
String sex = snrs.getString("sex");
Integer callTimes = snrs.getInt("callTimes");
Integer correctTimes = snrs.getInt("correctTimes");
Float rate = snrs.getFloat("rate");
student = new Students(bid, sid, sname, sex, callTimes, correctTimes, rate);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return student;
}
public Students callUpb (Integer cbid) {
String sql = "select * from students where bid <=? limit 1";
PreparedStatement qps = sUtil.createStatement(sql);
ResultSet snrs ;
Students student = null;
try {
qps.setInt(1,cbid);
snrs = qps.executeQuery();
while(snrs.next()) {
Integer bid = snrs.getInt("bid");
String sid = snrs.getString("sid");
String sname = snrs.getString("sname");
String sex = snrs.getString("sex");
Integer callTimes = snrs.getInt("callTimes");
Integer correctTimes = snrs.getInt("correctTimes");
Float rate = snrs.getFloat("rate");
student = new Students(bid, sid, sname, sex, callTimes, correctTimes, rate);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return student;
}
3.*数据库读写部分
使用JDBC工具类降低与MySQL数据库建立通信的复杂度,使用Dao封装,将用户请求转化为sql语句,并将结果返回相应的servlet。
JDBC部分
package com.classrollcall.util;
import java.sql.*;
/**
* Demo class
*
* @author iii
*/
public class JdbcUtil {
private Connection con = null;
private PreparedStatement ps = null;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("Driver接口实现类被注册");
}
public Connection createCon(){
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/class","root","admin");
} catch (SQLException throwables) {
throwables.printStackTrace();
System.out.println("Connection对象创建失败");
}
return con;
}
public PreparedStatement createStatement(String sql){
Connection con = createCon();
try {
ps = con.prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return ps;
}
public void close(){
if(ps!=null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public void close (ResultSet rs ){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
close();
}
}
StudentDao部分
package com.classrollcall.Dao;
import com.classrollcall.entity.Students;
import com.classrollcall.util.JdbcUtil;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
/**
* @author iii
*/
public class StudentDao {
final private JdbcUtil sUtil = new JdbcUtil();
/**
* 学生注册
*/
public int studentAdd (Students student){
String sql = "insert into students(sid,sname,sex,callTimes,correctTimes,rate)" +
"values(?,?,?,?,?,?)";
int sresult = 0;
try {
PreparedStatement sps = sUtil.createStatement(sql);
sps.setString(1,student.getSid());
sps.setString(2,student.getSname());
sps.setString(3,student.getSex());
sps.setInt(4,student.getCallTimes());
sps.setInt(5,student.getCorrectTimes());
sps.setFloat(6,student.getRate());
sresult = sps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
sUtil.close();
}
return sresult;
}
/**
* 学生查询
*/
public ArrayList<Students> sfindAll() {
String sql = "select * from students";
PreparedStatement sps = sUtil.createStatement(sql);
ResultSet srs = null;
ArrayList<Students> studentList = new ArrayList<>();
try {
srs = sps.executeQuery();
while (srs.next()) {
Integer bid = srs.getInt("bid");
String sid = srs.getString("sid");
String sname = srs.getString("sname");
String sex = srs.getString("sex");
Integer callTimes = srs.getInt("callTimes");
Integer correctTimes = srs.getInt("correctTimes");
Float rate = srs.getFloat("rate");
Students students = new Students (bid,sid,sname,sex,callTimes,correctTimes,rate);
studentList.add(students);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
sUtil.close(srs);
}
return studentList;
}
/**
* 点名
*/
public Students callUp(Integer cbid) {
String sql = "select * from students where bid >=? limit 1";
PreparedStatement qps = sUtil.createStatement(sql);
ResultSet snrs ;
Students student = null;
try {
qps.setInt(1,cbid);
snrs = qps.executeQuery();
while(snrs.next()) {
Integer bid = snrs.getInt("bid");
String sid = snrs.getString("sid");
String sname = snrs.getString("sname");
String sex = snrs.getString("sex");
Integer callTimes = snrs.getInt("callTimes");
Integer correctTimes = snrs.getInt("correctTimes");
Float rate = snrs.getFloat("rate");
student = new Students(bid, sid, sname, sex, callTimes, correctTimes, rate);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return student;
}
public Students callUpb (Integer cbid) {
String sql = "select * from students where bid <=? limit 1";
PreparedStatement qps = sUtil.createStatement(sql);
ResultSet snrs ;
Students student = null;
try {
qps.setInt(1,cbid);
snrs = qps.executeQuery();
while(snrs.next()) {
Integer bid = snrs.getInt("bid");
String sid = snrs.getString("sid");
String sname = snrs.getString("sname");
String sex = snrs.getString("sex");
Integer callTimes = snrs.getInt("callTimes");
Integer correctTimes = snrs.getInt("correctTimes");
Float rate = snrs.getFloat("rate");
student = new Students(bid, sid, sname, sex, callTimes, correctTimes, rate);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return student;
}
public Students callUp(Integer cbid,Integer e ) {
String sql ="select * from students order by rate desc limit ?;";
PreparedStatement qps = sUtil.createStatement(sql);
ResultSet snrs;
ArrayList <Students>studentList = new ArrayList<>();
try {
snrs = qps.executeQuery();
qps.setInt(1,e);
while (snrs.next()){
Integer bid = snrs.getInt("bid");
String sid = snrs.getString("sid");
String sname = snrs.getString("sname");
String sex = snrs.getString("sex");
Integer callTimes = snrs.getInt("callTimes");
Integer correctTimes = snrs.getInt("correctTimes");
Float rate = snrs.getFloat("rate");
Students students = new Students(bid, sid, sname, sex, callTimes, correctTimes, rate);
studentList.add(students);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return studentList.get(cbid);
}
/**
* 点名结果返回
*/
public int callStudent(Integer result,String bid){
if(result == 1){
String sql ="update students set callTimes =callTimes+1,correctTimes=correctTimes+1 ,rate=correctTimes/callTimes where bid = ?";
PreparedStatement dps = sUtil.createStatement(sql);
int dresult = 0;
try {
dps.setInt(1,Integer.parseInt(bid));
dresult = dps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
sUtil.close();
}
return dresult;
}
else {
String sql ="update students set callTimes =callTimes+1,rate=correctTimes/callTimes where bid = ?";
PreparedStatement dps = sUtil.createStatement(sql);
int dresult = 0;
try {
dps.setInt(1,Integer.parseInt(bid));
dresult = dps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
sUtil.close();
}
return dresult;
}
}
/**
* 学生删除
*/
public int delete (String bid){
String sql ="delete from students where bid=?";
PreparedStatement ps = sUtil.createStatement(sql);
int result = 0;
try {
ps.setInt(1,Integer.parseInt(bid));
result = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
sUtil.close();
}
return result;
}
/**
* 获取学生数
*/
public int count(){
String sql = "select * from students";
PreparedStatement sps = sUtil.createStatement(sql);
ResultSet srs = null;
int i = 0;
try {
srs = sps.executeQuery();
while (srs.next()) {
i++;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
sUtil.close(srs);
}
return i;
}
/**
* 清空表
*/
public int clear() {
String sql = "truncate students;";
PreparedStatement ps = sUtil.createStatement(sql);
int result= 0;
try {
result = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
sUtil.close();
}
return result;
}
}
UserDao部分
package com.classrollcall.Dao;
import com.classrollcall.entity.Users;
import com.classrollcall.util.JdbcUtil;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
/**
* @author iii
*/
public class UserDao {
private final JdbcUtil util = new JdbcUtil();
/**
* 用户注册
*/
public int add(Users user) {
String sql = "insert into users(userName,password,sex,email)" +
"values(?,?,?,?)";
int result = 0;
try {
PreparedStatement ps = util.createStatement(sql);
ps.setString(1, user.getUserName());
ps.setString(2, user.getPassword());
ps.setString(3, user.getSex());
ps.setString(4, user.getEmail());
result = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
util.close();
}
return result;
}
/**
* 用户查询
*/
public ArrayList<Users> findAll() {
String sql = "select * from users";
PreparedStatement ps = util.createStatement(sql);
ResultSet rs = null;
ArrayList <Users>userList = new ArrayList<>();
try {
rs = ps.executeQuery();
while (rs.next()) {
Integer userId = rs.getInt("userId");
String userName = rs.getString("userName");
String password = rs.getString("password");
String sex = rs.getString("sex");
String email = rs.getString("email");
Users users = new Users(userId, userName, password, sex, email);
userList.add(users);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
util.close(rs);
}
return userList;
}
/**
* 用户删除
*/
public int delete(String userId) {
String sql = "delete from users where userId=?";
PreparedStatement ps = util.createStatement(sql);
int result = 0;
try {
ps.setInt(1, Integer.parseInt(userId));
result = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
util.close();
}
return result;
}
/**
* 用户登陆
*/
public int login(String userName, String password) {
String sql = "select count(*) from users where userName= ? and password =?";
PreparedStatement ps = util.createStatement(sql);
ResultSet rs = null;
int result = 0;
try {
ps.setString(1, userName);
ps.setString(2, password);
rs = ps.executeQuery();
while (rs.next()) {
result = rs.getInt("count(*)");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
util.close(rs);
}
return result;
}
}
4.网页与serlet的数据记录
在实现优势点名的功能时,不知道怎么记录用户点击学生回答错误的次数,及实时检测数据达到n值时,在下一次调用优势点名的servlet。
解决方式就是通过建立全局共享对象记录n值及保存设置n值后n值的更新结果实现答错次数在CalledStudentServlet与ClassRollcallSerlet之间的共享,最后经过判断两个值的大小关系使负责点名的ClassRollCalllServlet采用不同的点名方式。
ServletContext application = req.getServletContext();
if(application.getAttribute("wrongtimes") == null){
application.setAttribute("wrongtimes",0);
}
if((int)application.getAttribute("wrongtimes")==5)
{
student = sdao.callUp(random.nextInt()*5,5);
application.setAttribute("wrongtimes",0);
}
else{
if( (student = sdao.callUp(hbid))== null){
student = sdao.callUpb(hbid);
}
}
5.*文件上传及请求转发
文件上传部分借鉴了网上的代码,其中有一个请求转发到jsp页面,并在页面上显示文件上传的结果,通过学习后,借用message的jsp页面返回n值的设置结果。
文件上传部分
package com.classrollcall.controller;
import java.io.*;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.classrollcall.Dao.StudentDao;
import com.classrollcall.entity.Students;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* @author iii
*/
public class UploadServlet extends HttpServlet {
@Override
public void doPost (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("UTF-8");
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = "D:/workspace/upload";
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+"目录不存在,需要创建");
//创建目录
boolean result=file.mkdir();
if(!result){
System.out.println("创建成功" );
}
}
//消息提示
String message = "";
try{
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if(!ServletFileUpload.isMultipartContent(request)){
//按照传统方式获取数据
return;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for(FileItem item : list){
//如果fileitem中封装的是普通输入项的数据
if(item.isFormField()){
String name = item.getFieldName();
item.getString("UTF-8");
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
System.out.println(name + "=" + value);
}else{//如果fileitem中封装的是上传文件
//得到上传的文件名称,
String filename = item.getName();
System.out.println(filename);
if(filename==null || "".equals(filename.trim())){
continue;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename=filename.substring(filename.lastIndexOf("\\")+1);
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
BufferedReader br;
br = new BufferedReader(new InputStreamReader(in));
StudentDao dao =new StudentDao();
Students student ;
while (true) {
String line = br.readLine();
if (null == line) {
break;
}
String [] digitWord = line.split("\\s");
student = new Students(null,digitWord[0],digitWord[1],digitWord[2],Integer.valueOf(digitWord[3]),Integer.valueOf(digitWord[4]),Float.valueOf(digitWord[5]));
dao.studentAdd(student);
}
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
//创建一个缓冲区
byte[] buffer = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int len ;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while((len=in.read(buffer))>0){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0, len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!";
}
}
}catch (Exception e) {
message= "文件上传失败!";
e.printStackTrace();
}
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
设置n值结果返回部分
ServletContext application = req.getServletContext();
int n;
String message ="设置成功" ;
if(application.getAttribute("n") == null){
application.setAttribute("n",5);
}
n = Integer.parseInt(req.getParameter("n值"));
application.setAttribute("n",n);
req.setAttribute("message",message);
req.getRequestDispatcher("/message.jsp").forward(req, resp);
}
}
6.数据库设计
简述数据库设计:建立一个数据库为class,其中有两张表分别为students和users。Student与user的表编号采用自增标签,用户编号及学生编号设置为不允许空值。
数据库表设计的截图: