1.缘起
刚刚接触一点JavaWeb,会一点Servlet和JSP,所以想写点东西,巩固一下知识。因为刚刚入门,本着能做出来就行的目标完成了这个《学生管理系统》小项目。写博客就是想梳理一下流程,回顾一下,大佬请绕道。
2. 使用的技术
前端:HTML+CSS+Bootstrap
后台:JSP+Servlet
数据库:MySQL(JDBC)
3.实现的功能以及截图
- Bootstrap实现具有轮播背景的登陆页面
- 学生信息的增删改查(可以根据学生id或学生name查询)
- 实现了分页
- 修改管理员信息
- 退出系统
1.登陆页面
2.主页面
3.添加学生信息页面
4.更新学生信息页面
5.修改管理员信息页面
4.核心步骤
1.JDBC的封装,因为在进行数据库的操作中,有很多步骤是重复的,而且一些步骤和sql语句无关,我们可以将其封装成一个工具类,这将大大减小代码量,更便于维护。
DBUtil
package cn.yf.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBUtil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/sms?characterEncoding=UTF-8";
private static final String NAME = "root";
private static final String PASSWORD="admin";
public static Connection connection = null;
public static PreparedStatement ps = null;
public static ResultSet rs = null;
//获得连接
public static Connection getConnection(){
try{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, NAME, PASSWORD);
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}
return connection;
}
//获得PreparedStatement
public static PreparedStatement getPreparedStatement(String sql,Object[] params){
try{
ps = DBUtil.getConnection().prepareStatement(sql);
if(params != null){
for(int i=0; i<params.length; i++){
//这里是从1开始的
ps.setObject(i+1, params[i]);
}
}
}catch(SQLException e){
e.printStackTrace();
}
return ps;
}
//关闭
public static void close(Connection c, PreparedStatement ps, ResultSet rs){
try{
if(rs != null) rs.close();
if(ps != null) ps.close();
if(rs != null) rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
//通用的增删改
public static boolean generalUpdate(String sql, Object[] params){
ps = DBUtil.getPreparedStatement(sql, params);
int count = -1;
try {
count = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(count>0){
return true;
}else{
return false;
}
}
//通用的查询(条件查询)
public static ResultSet generalQuery(String sql, Object[] params){
ps = DBUtil.getPreparedStatement(sql, params);
try {
rs = ps.executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
//查询数据库中的所有数据个数
public static int QueryAll(String sql){
int count = 0;
try {
rs = DBUtil.generalQuery(sql, null);
if(rs.next()){
count = rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return count;
}
}
这里需要注意的有2点:
1.对数据库的操作,整体来说分二种,第一种就是增删改也就是ps.executeUpdate(),它的返回值类型是int,代表的意思是成功操作的个数,所以这里我们只需要根据它的返回值是不是大于0即可判断是否执行成功。第二种就是查询ps.executeQuery(),因为不同的查询返回的东西不一样,我们在工具类中统一返回ResultSet。
2.因为sql语句的不同,我们需要从外面传入sql语句,而且sql语句中是有参数的,并且不知道参数的类型,这里我们用一个Object[]数组来存放这些参数。并且使用ps.setObject(i+1, params[i]);设置这些参数。这里需要注意的是PreparedStatement对象中的setObject是基于1的所有这里我们使用i+1。
到这里我们的JDBC已经封装好,对于不同的数据库操作,我们只需要准备好sql语句,以及相应的参数,调用DBUtil即可
下面是StudentDao代码
package cn.yf.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import cn.yf.entity.Student;
import cn.yf.util.DBUtil;
import cn.yf.util.DateUtil;
public class StudentDao {
//添加学生
public boolean addStudent(Student student){
String sql = "insert into student values(null,?,?,?,?,?,?)";
Object params[] = {student.getName(),
student.getSex(),student.getBirth(),student.getSchoolday(),student.getMarjor_id(),student.getCollege_id()};
boolean result = DBUtil.generalUpdate(sql, params);
return result;
}
//删除学生(根据id删除)
public boolean deleteStudent(int id){
String sql = "delete from student where id = ?";
Object[] params = {id};
boolean result = DBUtil.generalUpdate(sql, params);
return result;
}
//根据id修改学生信息
public boolean updateStudent(int id,Student student){
String sql = "update student set name=?,sex=?,birth=?,schoolday=?,marjor_id=?,college_id=? where id = ?";
Object[] params = {student.getName(),student.getSex(),student.getBirth(),student.getSchoolday(),student.getMarjor_id(),student.getCollege_id(),id};
boolean result = DBUtil.generalUpdate(sql, params);
return result;
}
//查询所有学生
public List<Student> queryAllStudent(){
List<Student> students = new ArrayList<Student>();
Student s = null;
try {
String sql = "select * from student";
ResultSet rs = DBUtil.generalQuery(sql, null);
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
int sex = rs.getInt("sex");
Date birth = DateUtil.t2d(rs.getTimestamp("birth"));
Date schoolday = DateUtil.t2d(rs.getTimestamp("schoolday"));
int marjor_id = rs.getInt("marjor_id");
int college_id = rs.getInt("college_id");
s = new Student(id,name,sex,birth,schoolday,marjor_id,college_id);
students.add(s);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return students;
}
//根据id查询
public List<Student> queryStudentById(int id){
Student s = null;
List<Student> students = new ArrayList<Student>();
try {
String sql = "select * from student where id = ?";
Object[] params = {id};
ResultSet rs = DBUtil.generalQuery(sql, params);
while(rs.next()){
int id1 = rs.getInt("id");
String name = rs.getString("name");
int sex = rs.getInt("sex");
Date birth = DateUtil.t2d(rs.getTimestamp("birth"));
Date schoolday = DateUtil.t2d(rs.getTimestamp("schoolday"));
int marjor_id = rs.getInt("marjor_id");
int college_id = rs.getInt("college_id");
s = new Student(id1,name,sex,birth,schoolday,marjor_id,college_id);
students.add(s);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return students;
}
//根据姓名查询
public List<Student> queryStudentByName(String name){
List<Student> students = new ArrayList<Student>();
Student s = null;
try {
String sql = "select * from student where name = ?";
Object[] params = {name};
ResultSet rs = DBUtil.generalQuery(sql, params);
while(rs.next()){
int id1 = rs.getInt("id");
String name1 = rs.getString("name");
int sex = rs.getInt("sex");
Date birth = DateUtil.t2d(rs.getTimestamp("birth"));
Date schoolday = DateUtil.t2d(rs.getTimestamp("schoolday"));
int marjor_id = rs.getInt("marjor_id");
int college_id = rs.getInt("college_id");
s = new Student(id1,name1,sex,birth,schoolday,marjor_id,college_id);
students.add(s);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return students;
}
//查询Student表中的数据个数
public int QueryAll(){
String sql = "select count(*) from student";
return DBUtil.QueryAll(sql);
}
//查询当前页的数据
public List<Student> queryCurrentPage(int currentPage,int pageSize){
String sql = "SELECT * FROM STUDENT LIMIT ?,?";
Object[] params = {(currentPage-1)*pageSize,pageSize};
ResultSet rs = DBUtil.generalQuery(sql, params);
Student s = null;
List<Student> students = new ArrayList<>();
try {
while(rs.next()){
int id1 = rs.getInt("id");
String name1 = rs.getString("name");
int sex = rs.getInt("sex");
Date birth = DateUtil.t2d(rs.getTimestamp("birth"));
Date schoolday = DateUtil.t2d(rs.getTimestamp("schoolday"));
int marjor_id = rs.getInt("marjor_id");
int college_id = rs.getInt("college_id");
s = new Student(id1,name1,sex,birth,schoolday,marjor_id,college_id);
students.add(s);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return students;
}
}
2.前端遇到的一些问题
1.我的主页面使用的是frameset框架页面
<frameset rows="20%,*" frame framespacing="10">
<frame src="top.jsp" noresize="noresize" scrolling="no" />
<frameset cols="20%,*">
<frame src="Left_nav.jsp" noresize="noresize" />
<frame src="Page.jsp" name="contain"/>
</frameset>
</frameset>
有时候很多时候要进行页面跳转,我们在跳转的时候,一定要加上target="_parent"这个属性,不然它会在子页面中跳转。
3.如何分页
我们设想一下,假如我们要进行分页,我们在页面的时候,点击下一页的时候,我们需要给后台传什么值?
当然是当前页,以及一页有多少条数据。
因为我使用的MySQL,所以首先来讲一下实现分页的sql语句,SELECT * FROM TABLE LIMIT A,B
这个sql语句的意思就是从a条数据开始,数b条数据出来。这就是我们分页的sql原理。
我们将当前页用currentPage,页面大小用pageSize表示,因为MySQL是基于0的,那么此时的sql语句是,SELECT * FROM TABLE LIMIT (currentPage-1)pageSize,pageSize。
为了帮助我们实现分页,我们需要准备一个分页帮助类Page
package cn.yf.entity;
import java.util.List;
public class Page {
//当前页
private int currentPage;
//页面大小
private int pageSize;
//数据总数
private int totalCount;
//总页数
private int totalPage;
//当前页的数据集合
private List<Student> students;
public Page() {
super();
// TODO Auto-generated constructor stub
}
public Page(int currentPage, int pageSize, int totalCount, int totalPage, List<Student> students) {
super();
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.totalPage = totalPage;
this.students = students;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getpageSize() {
return pageSize;
}
public void setpageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Page [currentPage=" + currentPage + ", pageSize=" + pageSize + ", totalCount=" + totalCount
+ ", totalPage=" + totalPage + ", students=" + students + "]";
}
}
我们还需要知道数据总数(totalCount)以及每页的数据集合(students),这个我们可以通过封装好的DBUtil实现
//查询Student表中的数据个数
public int QueryAll(){
String sql = "select count(*) from student";
return DBUtil.QueryAll(sql);
}
//查询当前页的数据
public List<Student> queryCurrentPage(int currentPage,int pageSize){
String sql = "SELECT * FROM STUDENT LIMIT ?,?";
Object[] params = {(currentPage-1)*pageSize,pageSize};
ResultSet rs = DBUtil.generalQuery(sql, params);
Student s = null;
List<Student> students = new ArrayList<>();
try {
while(rs.next()){
int id1 = rs.getInt("id");
String name1 = rs.getString("name");
int sex = rs.getInt("sex");
Date birth = DateUtil.t2d(rs.getTimestamp("birth"));
Date schoolday = DateUtil.t2d(rs.getTimestamp("schoolday"));
int marjor_id = rs.getInt("marjor_id");
int college_id = rs.getInt("college_id");
s = new Student(id1,name1,sex,birth,schoolday,marjor_id,college_id);
students.add(s);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return students;
}
当我们知道数据总数和页面大小后,页面的总数量(totalPage)就可以求出来
totalPage = totalCount%pageSize==0?totalCount/pageSize:totalCount/pageSize+1;
这样我们分页所需要的五个值,就都得到了,我们只需要将其封装成Page对象然后传到jsp页面即可
分页的Servlet
package cn.yf.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.yf.entity.Page;
import cn.yf.entity.Student;
import cn.yf.service.StudentService;
/**
* Servlet implementation class QueryStudentByPage
*/
@WebServlet("/QueryStudentByPage")
public class QueryStudentByPage extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
StudentService service = new StudentService();
// student表数据数总数
int totalCount = service.QueryAll();
// 每页的大小
int pageSize = 10;
// 总页数
int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
// 当前页
String passPage = request.getParameter("passPage");
int currentPage = -1;
if (passPage == null) {
passPage = "1";
currentPage = Integer.parseInt(passPage);
}else if(Integer.parseInt(passPage)>=totalPage){
currentPage = totalPage;
}else if(Integer.parseInt(passPage)<=1){
currentPage = 1;
}else{
currentPage = Integer.parseInt(passPage);
}
// 当前页的数据集合
List<Student> students = service.queryCurrentPage(currentPage, pageSize);
Page page = new Page();
page.setTotalCount(totalCount);
page.setpageSize(pageSize);
page.setStudents(students);
page.setCurrentPage(currentPage);
page.setTotalPage(totalPage);
HttpSession session = request.getSession();
session.setAttribute("page", page);
response.sendRedirect("main.jsp");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
这里我们做了一个判断,因为当我们第一次访问时,是没有当前页的值的,这个为空,所有我们设置,如果当前页为空,我们给他一个值为1,也就是第一页。
分页的jsp
<%@page import="cn.yf.entity.Page"%>
<%@page import="cn.yf.entity.Student"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery/2.0.0/jquery.min.js"></script>
<link rel="stylesheet" href="css/bootstrap/3.3.6/bootstrap.min.css" target="_blank" rel="external nofollow" />
<script type="text/javascript" src="js/bootstrap/3.3.6/bootstrap.min.js"></script>
<link rel="stylesheet" href="css/main.css" target="_blank" rel="external nofollow" />
<script type="text/javascript">
function check(){
var idorName = document.getElementById("IdorName").value;
if(idorName == ""){
alert("ID不能为空!");
return false;
}
return true;
}
function remove(){
var result = confirm("请确认是否删除!");
if(result){
return true;
}
return false;
}
</script>
</head>
<body>
<% Page p = (Page)session.getAttribute("page"); %>
<div id="Student">
<div id="Student_top">
<div id="Student_title">
<h3>学生学籍管理</h3>
</div>
<div id="Student_search">
<form action="queryByIdOrNameServlet" method="post" onsubmit="return check()" target="_parent">
<input type="text" placeholder="请输入ID" class="form-control"
style="width: 250px; float: left;" id="IdorName" name="IdorName" /> <input type="submit"
value="搜索" class="btn btn-primary" style="float: right;" />
</form>
</div>
<div id="Student_add">
<input class="btn btn-success" value="添加学生" style="width: 100px;" onclick="location='addStudent.jsp?passPage=<%=p.getTotalPage() %>'"/>
</div>
</div>
<div id="hr"></div>
<div id="Student_List" style="margin-left: 20px">
<table id="Student_table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>出生日期</th>
<th>入学日期</th>
<th>所属专业</th>
<th>所需学院</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<%
List<Student> students = p.getStudents();
for (Student s : students) {
%>
<tr>
<td><%=s.getId()%></td>
<td><%=s.getName()%></td>
<td><%=s.getSex()%></td>
<td><%=s.getBirth()%></td>
<td><%=s.getSchoolday()%></td>
<td><%=s.getMarjor_id()%></td>
<td><%=s.getCollege_id()%></td>
<td>
<button class="btn btn-primary" onclick="location='updateStudent.jsp?id=<%=s.getId() %>&passPage=<%=p.getCurrentPage() %>'">修改</button>
<a href="deleteStudentServlet?id=<%=s.getId()%>&passPage=<%=p.getCurrentPage()%>" target="_blank" rel="external nofollow" target="_parent" onclick="return remove()"><button class="btn btn-danger">删除</button></a>
</td>
</tr>
<%
}
%>
</tbody>
</table>
</div>
<div id="Page" style="margin-top: 40px; margin-left: 400px;">
<a href="QueryStudentByPage?passPage=1" target="_blank" rel="external nofollow" target="_parent"><button class="btn btn-info" >首页</button></a>
<a style="margin: 0 10px" target="_parent" href="QueryStudentByPage?passPage=<%=p.getCurrentPage()-1%>" target="_blank" rel="external nofollow" ><button class="btn btn-info">上一页</button></a>
<a style="margin-right: 10px" target="_parent" href="QueryStudentByPage?passPage=<%=p.getCurrentPage()+1%>" target="_blank" rel="external nofollow" ><button class="btn btn-info">下一页</button></a>
<a href="QueryStudentByPage?passPage=<%= p.getTotalPage() %>" target="_blank" rel="external nofollow" target="_parent"><button class="btn btn-info">尾页</button></a>
</div>
</div>
</body>
</html>
4.页面跳转的一些问题
在页面跳转中有form表单跳转,也有a标签,button按钮。
当需要传值的时候,大多数是通过在url后面加上数据。也有在request,session域中设置属性。
在整个项目中设置了一个session属性,也就是管理员的姓名这个属性,一直存放在session中,因此,不管在什么页面,我们的top.jsp都可以取到当前session中的管理员姓名
login.jsp
HttpSession session = request.getSession();
session.setAttribute("name", name);
top.jsp
<div class="well" id="top"><h1>您好!${sessionScope.name},欢迎使用学生管理系统</h1></div>
但是,当我们修改管理信息后,就会将session中的name重置。
updateAdminServlet
session.setAttribute("name", name1);
5.总结
这个小项目花了我2,3天的空闲时间,因为前端很废时间,而且一些控件在ie上面跑不起来。做的时候也有各种各样的小问题,都是通过百度解决的。等我学习了框架,AJAX,可能还会写一个功能更加完善的学生管理系统Plus,没有使用AJAX真的很奇怪,因为点啥都会刷一下,感觉就很奇怪(主要是我还不会)。