基于javaweb的web资源库项目——后台用户管理实现
后台整体页面结构
用户分为学生,教师,管理员,而管理员登录时会跳转到后台的欢迎页面。
通过观察可以知道不管是欢迎页面,还是学生或教师以及后面的资源等的管理页面都有相同的页面结构,如下所示
那么这样就可以把相同的页面结构单独抽取成一个jsp,然后在不同的页面结构的jsp中通过include指令包含它。这样可以实现代码复用。
后台的所有页面以及处理后台的处于控制层的servlet都是要做权限控制,到后面会用过滤器实现,这里就先不讲
过滤器实现的原理就是过滤路径,所有需要有一个路径标识,在这里使用manage路径标识
在after文件夹中创建子文件夹manage,然后再manage中创建相同的页面结构admin_menu.jsp,代码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>web资源库管理系统</title>
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/views/css/common.css" />
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/views/css/main.css" />
</head>
<body>
<div class="topbar-wrap white">
<div class="topbar-inner clearfix">
<div class="topbar-logo-wrap clearfix">
<ul class="navbar-list clearfix">
<li><a class="on"
href="${pageContext.request.contextPath}/views/after/manage/admin_index.jsp">首页</a></li>
<li><a
href="${pageContext.request.contextPath}/views/before/manage/index.jsp"
target="_blank">网站首页</a></li>
</ul>
</div>
<div class="top-info-wrap">
<ul class="top-info-list clearfix">
<li><a href="#">管理员:${name.userName}</a></li>
<li><a
href="${pageContext.request.contextPath}/manage/admin_logout">退出</a></li>
</ul>
</div>
</div>
</div>
<div class="container clearfix">
<div class="sidebar-wrap">
<div class="sidebar-title">
<h1>菜单</h1>
</div>
<div class="sidebar-content">
<ul class="sidebar-list">
<li><a href="#"><i class="icon-font"></i>用戶管理</a>
<ul class="sub-menu">
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_student_select"><i
class="icon-font"></i>学生管理</a></li>
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_teacher_select"><i
class="icon-font"></i>教师管理</a></li>
</ul></li>
<li><a href="#"><i class="icon-font"></i>资源管理</a>
<ul class="sub-menu">
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_resource_select"><i
class="icon-font"></i>资源管理</a></li>
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_category_select"><i
class="icon-font"></i>类别管理</a></li>
</ul></li>
<li><a href="#"><i class="icon-font"></i>论坛管理</a>
<ul class="sub-menu">
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_post_select"><i
class="icon-font"></i>帖子管理</a></li>
<li><a
href="${pageContext.request.contextPath}/manage/admin_do_comment_select"><i
class="icon-font"></i>评论管理</a></li>
</ul></li>
</ul>
</div>
</div>
后台欢迎页面结构
前面给了后台都有的整体的页面结构,现在只需在欢迎页面中使用include指令包含即可
在manage文件夹中创建后台欢迎页面admin_index.jsp,代码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="admin_menu.jsp"%>
<div class="main-wrap">
<div class="crumb-wrap">
<div class="crumb-list">
<div class="crumb-list">
<i class="icon-font"></i> <a
href="${pageContext.request.contextPath}/views/after/manage/admin_index.jsp">首页
</a>
</div>
<div align="center" style="padding-top: 250px;">
<font color="red" size="10">欢迎使用Web资源库管理系统</font>
</div>
</div>
</div>
</div>
</body>
</html>
在数据库中添加一个管理员账号
启动项目,在浏览器输入http://localhost:8080/web_resource/views/before/login.jsp登录账号,效果如下
用户管理实现
用户管理要实现功能如下
- 在页面上显示所有用户信息并且要实现分页
- 可以对用户进行增删改查,批量删除,学生还可以批量添加学生
在页面上显示所有学生信息并分页
后台学生管理页面
同样的,学生管理页面也是使用include指令包含整体的页面结构
后台学生管理页面使用了JSTL核心标签库,我们只需要导入该Jar包后,在页面中使用taglib指令将其导入即可使用
jar包下载地址
在manage文件夹下创建admin_student.jsp,代码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ include file="admin_menu.jsp"%>
<div class="main-wrap">
<div class="crumb-wrap">
<div class="crumb-list">
<i class="icon-font"></i><a
href="${pageContext.request.contextPath}/views/after/manage/admin_index.jsp">首页</a><span
class="crumb-step">></span><span class="crumb-name">学生管理</span>
</div>
</div>
<div class="search-wrap">
<div class="search-content">
<form action="admin_do_student_select" method="get">
<table class="search-tab">
<tr>
<th width="70">关键字:</th>
<td><input class="common-text" placeholder="关键字"
name="keywords" id="" type="text"></td>
<td><input class="btn btn-primary btn2" name="sub" value="查询"
type="submit"></td>
</tr>
</table>
</form>
</div>
</div>
<div id="register" class="result-wrap">
<form action="admin_do_student_delete" id="delectForm" method="post">
<div class="result-title">
<div class="result-list">
<a
href="${pageContext.request.contextPath}/views/after/manage/admin_student_add.jsp">
<i class="icon-font"></i>添加学生
</a> <a href="javascript:openAddRegisterDialog()"> <i
class="icon-font"></i>批量添加学生
</a> <a id="batchDel"
href="javascript:deleteMore('你确定删除这些用户吗?', 'delectForm')"> <i
class="icon-font"></i>批量删除
</a>
</div>
</div>
<div class="result-content">
<table class="result-tab" width="100%">
<tr>
<th class="tc" width="5%"><input class="allChoose" name=""
onclick="selAll(this)" type="checkbox"></th>
<th>账号</th>
<th>姓名</th>
<th>性别</th>
<th>生日</th>
<th>班级</th>
<th>操作</th>
</tr>
<c:forEach var="u" items="${userlist}">
<tr>
<td class="tc"><input name="id[]" value="${u.userId}"
type="checkbox"></td>
<td>${u.userId }</td>
<td>${u.userName }</td>
<td>${u.userSex }</td>
<td>${u.userBirthday }</td>
<td>${u.userClass }</td>
<td><a class="link-update"
href="${pageContext.request.contextPath}/manage/admin_to_student_update?id=${u.userId}¤tPage=${currentPage}">修改</a>
<a class="link-del"
href="javascript:Delete('你确定要删除用户【${u.userName} 】吗?', '${pageContext.request.contextPath}/manage/admin_do_student_delete?id=${u.userId}¤tPage=${currentPage }')">删除</a>
</td>
</tr>
</c:forEach>
</table>
<div class="list-page">
共 ${totalStudent} 条记录, 当前 ${currentPage} / ${totalPage} 页 <a
href="admin_do_student_select?currentPage=1">首页</a> <a
href="admin_do_student_select?currentPage=${currentPage - 1 < 1 ? 1 : currentPage-1}">上一页</a>
<a
href="admin_do_student_select?currentPage=${currentPage + 1 > totalPage ? totalPage : currentPage + 1}">下一页</a>
<a href="admin_do_student_select?currentPage=${totalPage}">尾页</a>
</div>
</div>
</form>
</div>
</div>
<script src="${pageContext.request.contextPath}/views/js/function.js"></script>
</body>
</html>
代码就不详细说明了,主要讲一下遍历学生信息
在servlet中会调用业务逻辑层获取到了用户点击某一页的学生信息存放在list集合中,并且放在了请求域中,那么在jsp页面中就可以使用EL表达式使用它
在 jsp页面中需要遍历集合,就需要使用JSTL的forEach标签,item属性的值是list集合对象,而var属性的值是对象变量名
也就是说每遍历一次var属性的值都是不同的对象,这样就可以通过EL表达式获取对象的属性值了
后端实现
数据访问层(dao)实现
检索用户点击的某一页的学生记录或检索用户搜索的学生姓名获取的学生记录
在页面上显示所有学生信息并分页,换句话说也就是当用户点击某一页时只检索那一页学生记录,那么在底层中就不能使用下面这条mysql语句
sql = "select * from user where user_level='学生'";
我们知道"select * from user where user_level=‘学生’ 会获取所有学生记录,但这不是我们想要的。
那么要怎么实现分页呢?只需在上面那条语句添加一个限制结果即可,如下
sql = "select * from user where user_level='学生' limit ?, ?";
limit是限制子句,第一个参数是数据库中的记录行数,第二参数是获取的记录条数,也就是从第一个参数中的行数开始检索,而第二个参数是检索的记录条数
很显然获取的记录条数就是每页显示的条数,而记录行数刚好等于(当前页 * 每页显示的条数)
用户除了通过点击页数来检索信息还之外还可以通过姓名来检索,可以添加一个通配符进行过滤即(like操作符),如下
sql = "select * from user where user_level='学生' and user_name like ? limit ?, ?";
通过上面的分析,只需要提供三个参数(当前页,用户搜索时提供的关键字(姓名),每一页的条数),完整代码如下
在dao层中的UserDao接口添加检索用户点击某一页的学生信息或检索关键词的学生信息的抽象方法,如下
public ArrayList<User> selectAllStudent(int currentPage, int count, String keyword) throws SQLException;
在dao层的实现类UserDaoImpl中重写接口方法selectAllStudent,如下
@Override
public ArrayList<User> selectAllStudent(int currentPage, int count, String keyword) throws SQLException {
ArrayList<User> listUser = new ArrayList<User>();
String sql = "";
if (keyword != null) {
sql = "select * from user where user_level='学生' and user_name like ? limit ?, ?";
resultSet = JDBCUtil.executeQuery(sql, "%" + keyword + "%", (currentPage - 1) * count, count);
} else {
sql = "select * from user where user_level='学生' limit ?, ?";
resultSet = JDBCUtil.executeQuery(sql, (currentPage - 1) * count, count);
}
while (resultSet.next()) {
User user = new User(resultSet.getString("user_id"), resultSet.getString("user_password"),
resultSet.getString("user_name"), resultSet.getString("user_sex"),
resultSet.getString("user_birthday"), resultSet.getString("user_class"),
resultSet.getString("user_level"));
listUser.add(user);
}
return listUser;
}
检索所有学生记录总数以及总页数
除了要实现分页,我们知道还得在页面上显示多少条记录,以及有几页,如下
sql = "select count(*) from user where user_level='学生'"
这条sql语句会检索并返回所有学生记录条数,也就是在页面上显示多少条记录,而总页数恰等于(总学生记录条数 / 每一页的记录条数)
同理,用户还可以通过关键字来检索,只需在上面这条sql语句中添加通配符(like操作符)即可,如下
sql = "select count(*) from user where user_level='学生' and user_name like ?"
通过上面的分析,只需要提供两个参数(用户搜索时提供的关键字(姓名),每一页的条数),完整代码如下
在dao层的UserDao接口中添加检索所有学生记录总数并算出总页数的抽象方法,如下
public int[] selectStudentTotal(int count, String keyword) throws SQLException;
在dao层的UserDaoImpl实现类中重写接口的selectStudentTotal方法,如下
@Override
public int[] selectStudentTotal(int count, String keyword) throws SQLException {
String sql = "";
int array[] = { 0, 1 };
if (keyword != null) {
sql = "select count(*) from user where user_level='学生' and user_name like ?";
resultSet = JDBCUtil.executeQuery(sql, "%" + keyword + "%");
} else {
sql = "select count(*) from user where user_level='学生'";
resultSet = JDBCUtil.executeQuery(sql);
}
while (resultSet.next()) {
array[0] = resultSet.getInt(1);
if (array[0] % count == 0) {
array[1] = array[0] / count;
} else {
array[1] = array[0] / count + 1;
}
}
return array;
}
业务逻辑层(service)实现
通过dao层的分析,可以知道service层要实现两个业务功能,它们封装了dao层操作,只提现业务
获取所有学生记录总数以及总页数
在service层的UserService中添加获取所有学生记录总数以及总页数业务抽象方法,如下
public int[] getStudentPageTotal(int count, String keyword) throws SQLException;
在service层的实现类UserServiceImpl中重写接口getStudentPageTotal方法,如下
@Override
public int[] getStudentPageTotal(int count, String keyword) throws SQLException {
int[] array = userDao.selectStudentTotal(count, keyword);
return array;
}
获取用户点击的某一页的学生记录或用户搜索的学生姓名获取的学生记录
在service层的UserService中添加获取用户点击的某一页的学生记录或用户搜索的学生姓名获取的学生记录的抽象方法,如下
public ArrayList<User> getAllStudentInfo(int currentPage, int count, String keyword) throws SQLException;
在service层的实现类UserServiceImpl中重写接口方法getAllStudentInfo,如下
@Override
public ArrayList<User> getAllStudentInfo(int currentPage, int count, String keyword) throws SQLException {
ArrayList<User> listUser = userDao.selectAllStudent(currentPage, count, keyword);
return listUser;
}
控制层(controller)实现
控制层主要功能就是接受客户端的数据,然后作为参数调用业务逻辑层获取数据,并把数据呈现在页面中
在控制层(controller)中的user包下创建DoStudentSelect.java,代码如下
package com.zhuo.controller.user;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
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 com.zhuo.entity.User;
import com.zhuo.service.impl.UserServiceImpl;
@WebServlet("/manage/admin_do_student_select")
public class DoStudentSelect extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int currentPage = 1;
int count = 5;
int array[] = { 0, 0 };
String cp = request.getParameter("currentPage");
String keyword = request.getParameter("keywords");
if (cp != null) {
currentPage = Integer.parseInt(cp);
}
UserServiceImpl userServiceImpl = new UserServiceImpl();
try {
array = userServiceImpl.getStudentPageTotal(count, keyword);
} catch (SQLException e) {
e.printStackTrace();
}
ArrayList<User> listUser = null;
try {
listUser = userServiceImpl.getAllStudentInfo(currentPage, count, keyword);
} catch (SQLException e) {
e.printStackTrace();
}
request.setAttribute("userlist", listUser);
request.setAttribute("totalStudent", array[0]);
request.setAttribute("totalPage", array[1]);
request.setAttribute("currentPage", currentPage);
request.getRequestDispatcher("/views/after/manage/admin_student.jsp").forward(request, response);
}
}
完成到这里,前后端功能就都实现了,测试前需要在数据库中添加学生信息,然后启动项目
删除学生和批量删除学生
后端实现
删除学生功能的实现,无非就是在servlet中通过request请求获取用户账号id,然后调用业务功能删除学生,而业务功能是封装了底层的sql操作,也就是一条delete语句
批量删除学生的实现,在servlet中获取的是用户账号id数组,只需遍历调用业务逻辑方法即可
控制层实现
在控制层的user包下创建DoStudentDelect.java,代码如下
package com.zhuo.controller.user;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
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 com.zhuo.service.impl.UserServiceImpl;
@WebServlet("/manage/admin_do_student_delete")
public class DoStudentDelete extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String id = request.getParameter("id");
UserServiceImpl userServiceImpl = new UserServiceImpl();
int count = 0;
try {
count = userServiceImpl.removeStudentInfo(id);
} catch (SQLException e) {
e.printStackTrace();
}
if (count > 0) {
response.sendRedirect("admin_do_student_select?currentPage=" + request.getParameter("currentPage"));
} else {
PrintWriter out = response.getWriter();
out.write("<script>");
out.write("alert('删除失败')");
out.write("location.href='admin_do_student_select?currentPage=" + request.getParameter("currentPage"));
out.write("</script>");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String ids[] = request.getParameterValues("id[]");
UserServiceImpl userServiceImpl = new UserServiceImpl();
int count = 0;
for (int i = 0; i < ids.length; i++) {
try {
count = userServiceImpl.removeStudentInfo(ids[i]);
} catch (SQLException e) {
e.printStackTrace();
}
}
if (count > 0) {
response.sendRedirect("admin_do_student_select");
} else {
PrintWriter out = response.getWriter();
out.write("<script>");
out.write("alert('批量删除失败')");
out.write(
"location.href='admin_do_student_select?currentPage=" + request.getParameter("currentPage") + "'");
out.write("</script>");
}
}
}
通过上面的servlet可以知道,删除单个学生用的是get请求,也就是用户点击删除按钮时会传给servlet一个用户id
批量删除学生信息用的是post请求,显然在页面中需要提供表单。
在前面的学生管理页面中,遍历学生记录的代码恰好就放在form表单中,并且遍历时还在表格中每一行的第一列提供了checkbox复选框,使用了EL表达式把checkbox的value设置为用户id
这样每一行的复选框就和每一行的用户对应了,当用户提交表单时会把选中的每一个复选框中的value值提交给servlet,这样就可以实现批量删除学生记录
业务逻辑层实现
在业务逻辑层的UserService接口中添加删除学生的业务逻辑抽象方法,如下
public int removeStudentInfo(String userId) throws SQLException;
在业务逻辑层的实现类UserServiceImpl中重写接口方法removeStudentInfo,如下
@Override
public int removeStudentInfo(String userId) throws SQLException {
int i = userDao.deleteStudent(userId);
return i;
}
数据访问层实现
在数据访问层的UserDao接口中添加删除学生记录的抽象方法,如下
public int deleteStudent(String userId) throws SQLException;
在数据访问层的实现类UserDaoImpl中重写接口方法deleteStudent,如下
@Override
public int deleteStudent(String userId) throws SQLException {
String sql = "delete from user where user_id=?";
int i = JDBCUtil.executeUpdate(sql, userId);
return i;
}
前端实现
用户点击删除和点击批量删除都是通过js实现的,下面分别介绍
删除单个用户
删除单个用户是get请求,即当用户点击删除会发送get请求,那么只需使用超链接并把href的属性值设置删除学生的servlet路径即可
但是删除时需要提示一个对话框,询问用户是否删除,那么就需要使用confirm方法,代码如下
function Delete(message, url) {
if (confirm(message)) {
location.href = url;
}
}
当用户点击删除便会执行这段j代码,第一个参数是提示信息,第二个参数是请求的servlet。这些参数在学生管理页面中已给出
批量删除用户
批量删除用户是post请求,是通过表单提交的,所以js代码需要获取表单对象
checkbox复选框中的name属性值都是id[],这样在js通过name属性值获取就是checkbox对象数组,那么就需要遍历这些对象数组,并检查checkbox有没有被选中,若没被选中,则禁止提交表单,代码如下
function deleteMore(message, formName) {
if (confirm(message)) {
var form = document.getElementById(formName);
var flag = false;
var a = document.getElementsByName('id[]');
for (var i = 0; i < a.length; i++) {
if (a[i].checked) {
flag = true;
break;
}
}
if (flag) {
form.submit();
} else {
alert("请选择学生后在批量删除!");
}
}
}
通过全选复选框选中所有checkbox
checkbox即可以通过点击每一个复选框,也可以通过一个全选复选框来选择所有的复选框,代码如下
function selAll(o) {
var a = document.getElementsByName('id[]');
for (var i = 0; i < a.length; i++) {
a[i].checked = o.checked;
}
}
到这里就可以测试删除功能了,启动项目
修改学生
修改学生以及后面添加学生是和前面是类似,这里就不再说得那么详细了,不懂得可以看注释
后端实现
当点击修改页面时会请求servlet,servlet会通过request获取账号id并作为业务逻辑方法的参数被调用得到用户数据,并放到请求域中,之后跳转到学生修改页面
在控制层的user包下创建ToStudentUpdate.java,代码如下
package com.zhuo.controller.user;
import java.io.IOException;
import java.sql.SQLException;
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 com.zhuo.entity.User;
import com.zhuo.service.impl.UserServiceImpl;
@WebServlet("/manage/admin_to_student_update")
public class ToStudentUpdate extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String id = request.getParameter("id");
UserServiceImpl userServiceImpl = new UserServiceImpl();
User user = null;
try {
user = userServiceImpl.getStudentInfo(id);
} catch (SQLException e) {
e.printStackTrace();
}
request.setAttribute("user", user);
request.setAttribute("currentPage", request.getParameter("currentPage"));
request.getRequestDispatcher("/views/after/manage/admin_student_modify.jsp").forward(request, response);
}
}
在业务逻辑层的UserService接口中添加获取学生信息的业务逻辑抽象方法,如下
public User getStudentInfo(String userId) throws SQLException;
在业务逻辑层的实现类UserServiceImpl中重写接口方法getStudentInfo,如下
@Override
public User getStudentInfo(String userId) throws SQLException {
User user = userDao.selectStudent(userId);
return user;
}
在数据访问层的UserDao接口中添加检索学生信息的抽象方法,如下
public User selectStudent(String id) throws SQLException;
在数据访问层的实现类UserDaoImpl中重写接口方法selectStudent,如下
@Override
public User selectStudent(String id) throws SQLException {
String sql = "select m.*, DATE_FORMAT(m.user_birthday, '%Y-%m-%d')birthday from user m where USER_ID=?";
resultSet = JDBCUtil.executeQuery(sql, id);
User user = null;
while (resultSet.next()) {
user = new User(resultSet.getString("user_id"), resultSet.getString("user_password"),
resultSet.getString("user_name"), resultSet.getString("user_sex"),
resultSet.getString("user_birthday"), resultSet.getString("user_class"),
resultSet.getString("user_level"));
}
return user;
}
上面实现了获取学生信息跳转的修改页面,但还需要一个处理用户提交修改学生信息的servlet
处理修改页面的servlet和获取学生信息是类似,区别是底层执行的update语句
在controller层的user包下创建DoStudentUpdate,代码如下
package com.zhuo.controller.user;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
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 com.zhuo.entity.User;
import com.zhuo.service.UserService;
import com.zhuo.service.impl.UserServiceImpl;
@WebServlet("/manage/admin_do_student_update")
public class DoStudentUpdate extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String userId = request.getParameter("userId");
String userPassword = request.getParameter("userPassword");
String userName = request.getParameter("userName");
String userSex = request.getParameter("userSex");
String userBirthday = request.getParameter("userBirthday");
String userClass = request.getParameter("userClass");
String userLevel = request.getParameter("userLevel");
User user = new User(userId, userPassword, userName, userSex, userBirthday, userClass, userLevel);
UserServiceImpl userServiceImpl = new UserServiceImpl();
int count = 0;
try {
count = userServiceImpl.modifyStudentInfo(user);
} catch (SQLException e) {
e.printStackTrace();
}
if (count > 0) {
response.sendRedirect("admin_do_student_select?currentPage=" + request.getParameter("currentPage"));
} else {
PrintWriter out = response.getWriter();
out.write("<script>");
out.write("alert('用户修改失败')");
out.write("location.href='admin_to_student_update?id=" + userId + "'");
out.write("</script>");
}
}
}
在service层的UserService接口中添加修改学生信息的业务逻辑抽象方法如下
public int modifyStudentInfo(User user) throws SQLException;
在service层的实现类UserServiceImpl中重写接口方法modifyStudentInfo,如下
@Override
public int modifyStudentInfo(User user) throws SQLException{
int i = userDao.updateStudent(user);
return i;
}
在dao层的UserDao接口中添加更新学生信息的抽象方法,如下
public int updateStudent(User user) throws SQLException;
在dao层的实现类UserDaoImpl中重写接口方法updateStudent,如下
@Override
public int updateStudent(User user) throws SQLException {
String sql = "update user set user_name=?, user_password=?,user_sex=?,user_birthday=DATE_FORMAT(?, '%y-%m-%d'),user_class=? where user_id = ?";
int i = JDBCUtil.executeUpdate(sql, user.getUserName(), user.getUserPassword(), user.getUserSex(),
user.getUserBirthday(), user.getUserClass(), user.getUserId());
return i;
}
至此后端修改功能均已完成,现在编写前端代码
后台学生修改页面
在manage文件下创建admin_student_modify.jsp,代码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="admin_menu.jsp"%>
<div class="main-wrap">
<div class="crumb-wrap">
<div class="crumb-list">
<i class="icon-font"> </i><a
href="${pageContext.request.contextPath}/views/after/manage/admin_index.jsp">首页</a>
<span class="crumb-step">></span> <a class="crumb-name"
href="${pageContext.request.contextPath}/manage/admin_do_student_select">学生管理</a>
<span class="crumb-step">></span><span>修改用户</span>
</div>
</div>
<div class="result-wrap">
<div class="result-content">
<form
action="${pageContext.request.contextPath}/manage/admin_do_student_update"
method="post" id="myform" name="myform">
<input type="hidden" name="userId" value="${user.userId }">
<input type="hidden" name="currentPage" value="${currentPage }">
<table class="insert-tab" width="100%">
<tbody>
<tr>
<th><i class="require-red">*</i>学生姓名:</th>
<td><input class="common-text required" id="title"
name="userName" size="50" value="${user.userName }" type="text">
</td>
</tr>
<tr>
<th><i class="require-red">*</i>登录密码:</th>
<td><input class="common-text required" id="title"
name="userPassword" size="50" value="${user.userPassword }"
type="text"></td>
</tr>
<tr>
<th>性别:</th>
<td><input type="radio" name="userSex" value='男'
${user.userSex=='男'?"checked":"" }>男 <input
type="radio" name="userSex" value='女'
${user.userSex=='女'?"checked":"" }>女</td>
</tr>
<tr>
<th>出生日期:</th>
<td><input class="common-text" name="userBirthday" size="50"
value="${user.userBirthday }" type="text"></td>
</tr>
<tr>
<th><i class="require-red">*</i>班级:</th>
<td><input class="common-text required" id="title"
name="userClass" size="50" value="${user.userClass }"
type="text"></td>
</tr>
<tr>
<th></th>
<td><input class="btn btn-primary btn6 mr10" value="提交"
type="submit"> <input class="btn btn6"
onClick="history.go(-1)" value="返回" type="button"></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
启动项目,测试
添加单个学生
添加单个学生所需要做的是,当用户点击添加时,需要跳转到学生添加页面,也就是表单
用户提交时,需要一个servlet来处理表单,即调用业务逻辑方法插入学生,但插入前需要先判读账号是否已经存在
后台添加学生页面
在manage文件夹下创建admin_student_add.jsp,代码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="admin_menu.jsp"%>
<div class="main-wrap">
<div class="crumb-wrap">
<div class="crumb-list">
<i class="icon-font"></i><a href="admin_index.jsp">首页</a><span
class="crumb-step">></span><a class="crumb-name"
href="${pageContext.request.contextPath}/manage/admin_do_student_select">学生管理</a><span
class="crumb-step">></span><span>添加学生</span>
</div>
</div>
<div class="result-wrap">
<div class="result-content">
<form
action="${pageContext.request.contextPath}/manage/admin_do_student_add"
method="post" id="myform" name="myform">
<table class="insert-tab" width="100%">
<tbody>
<tr>
<th><i class="require-red">*</i>账号:</th>
<td><input class="common-text required" id="title"
name="userId" size="50" value="" type="text" required></td>
</tr>
<tr>
<th><i class="require-red">*</i>登录密码:</th>
<td><input class="common-text required" id="title"
name="userPassword" size="50" value="" type="password" required>
</td>
</tr>
<tr>
<th><i class="require-red">*</i>学生姓名:</th>
<td><input class="common-text required" id="title"
name="userName" size="50" value="" type="text" required>
</td>
</tr>
<tr>
<th><i class="require-red">*</i>性别:</th>
<td><input type="radio" name="userSex" value="男"
checked="checked" />男 <input type="radio" name="userSex"
value="女" />女</td>
</tr>
<tr>
<th><i class="require-red">*</i>出生日期:</th>
<td><input class="common-text required" id="title"
name="userBirthday" size="50" value="" type="text" required>
</td>
</tr>
<tr>
<th><i class="require-red">*</i>班级:</th>
<td><input class="common-text required" id="title"
name="userClass" size="50" value="" type="text" required>
</td>
</tr>
<tr>
<th></th>
<td><input class="btn btn-primary btn6 mr10" value="提交"
type="submit"> <input class="btn btn6"
onClick="history.go(-1)" value="返回" type="button"></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
后端实现
在controller层的user包下创建DoStudentAdd.java,代码如下
package com.zhuo.controller.user;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
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 com.zhuo.entity.User;
import com.zhuo.service.impl.UserServiceImpl;
@WebServlet("/manage/admin_do_student_add")
public class DoStudentAdd extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
String userId = request.getParameter("userId");
String userName = request.getParameter("userName");
String userPassword = request.getParameter("userPassword");
String userSex = request.getParameter("userSex");
String userBirthday = request.getParameter("userBirthday");
String userClass = request.getParameter("userClass");
User user = new User(userId, userPassword, userName, userSex, userBirthday, userClass, "学生");
UserServiceImpl userServiceImpl = new UserServiceImpl();
int count = 0;
try {
count = userServiceImpl.checkIdRepeated(userId);
} catch (SQLException e) {
e.printStackTrace();
}
if (count > 0) {
PrintWriter out = response.getWriter();
System.out.println("out =" + out);
out.write("<script>");
out.write("alert('添加失败,账号已存在')");
out.write("</script>");
out.write("<script>");
out.write("window.location='" + request.getContextPath() + "/views/after/manage/admin_student_add.jsp'");
out.write("</script>");
} else {
try {
userServiceImpl.addStudent(user);
response.sendRedirect("admin_do_student_select");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
先通过request请求获取添加学生的信息,然后存放在用户实体中,之后调用检查账号是否已经存在的业务逻辑方法
若不存在,接着调用添加学生的业务逻辑方法
若存在则响应给用户添加失败的信息,并重新返回到添加页面
在service层的UserService接口中添加一个添加学生的业务逻辑方法,如下
public int addStudent(User user) throws SQLException;
在service层的实现类UserServiceImpl中重写接口方法addStudent,如下
@Override
public int addStudent(User user) throws SQLException{
int i = userDao.insertStudent(user);
return i;
}
在dao层的UserDao接口中添加插入学生的抽象方法,如下``
public int insertStudent(User user) throws SQLException;
在dao层的实现类UserDaoImpl中重写接口方法insertStudent,如下
@Override
public int insertStudent(User user) throws SQLException {
String sql = "insert into user values(?, ?, ?, ?, DATE_FORMAT(?, '%Y-%m-%d'), ?, ?)";
int i = JDBCUtil.executeUpdate(sql, user.getUserId(), user.getUserPassword(), user.getUserName(),
user.getUserSex(), user.getUserBirthday(), user.getUserClass(), user.getUserLevel());
return i;
}
启动项目测试
批量添加学生
jQuery easyUI的使用
批量添加学生是通过点击按钮弹出一个对话框来实现的,对话框包含一个表单和两个按钮(导入,关闭),表单只使用一个input文件类型的组件,点击可弹出文件对话框选择文件,这里使用JQuery easyUI实现这些操作
jQuery EasyUI 下载
在整体结构页面admin_menu.jsp的head标签内引用,如下
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/views/jquery-easyui-1.6.10/themes/default/easyui.css">
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/views/jquery-easyui-1.6.10/themes/icon.css">
<script type="text/javascript"
src="${pageContext.request.contextPath}/views/jquery-easyui-1.6.10/jquery.min.js"></script>
<script type="text/javascript"
src="${pageContext.request.contextPath}/views/jquery-easyui-1.6.10/jquery.easyui.min.js"></script>
在后台学生管理页面使用easyUI
前面说过批量添加学生不是一个页面,而是一个对话框,含有表单以及两个按钮。在easyUI实现对话框,只需在jsp页面中使用如下代码
<div id="dlg" class="easyui-dialog" style="width: 370px;height: 250px;padding: 10px 20px"
closed="true" buttons="#dlg-buttons">
</div>
表单要实现文件上传功能,需要在form内指定enctype属性并把值设为multipart/form-data,即包含多部分数据的请求,且请求方式必须改为post,只需在jsp提供如下代码
<form id="fm" method="post" enctype="multipart/form-data">
<input name="registerFile" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
application/vnd.ms-excel" class="easyui-filebox" plain="true" data-options="buttonText:'选择文件'" required/>
</form>
easyUI的表单不是通过提交上传到服务器的,因为form表单即没有指定action属性,也没有提供类型为submit的input组件
而是通过使用 easyui 表单(form)插件来改变表单(form)为 ajax 表单(form)。表单(form)提交所有字段到后台服务器,服务器处理和发送一些数据返回到前端页面。我们接收返回数据,并将它显示出来,这是通过在js编写脚本实现的,后面会给出
两个按钮(导入,关闭),当点击导入会上传文件,即通过使用 easyui 表单(form)插件来改变表单(form)为 ajax 表单(form)。当点击关闭时关闭对话框,js代码后面给出
<div id="dlg-buttons">
<a href="javascript:upload()" class="easyui-linkbutton" iconCls="icon-ok">导入</a>
<a href="javascript:closeDialog()" class="easyui-linkbutton" iconCls="icon-cancel">关闭</a>
</div>
综上,前面是代码片段分析,要想真正的使用它们,需要在admin_student.jsp的body标签之前使用即可,如下
我们需要点击按钮弹出对话框,也就是上面给的代码,需要下面的js代码,如下
var url;
function openAddRegisterDialog() {
$("#dlg").dialog("open").dialog("setTitle", "批量导入帐号");
url = "webresource/all_register?flagText=addRegister";
}
还需要一个点击关闭按钮,关闭对话框的js代码,如下
function closeDialog() {
$("#dlg").dialog("close");
}
同理,点击导入时,需要把表单转化为ajax上传到服务器,js代码如下
function upload() {
$("#fm").form("submit", {
url: url,
onSubmit: function() {
return $(this).form("validate");
},
success: function(result) {
var json = $.parseJSON(result);
console.info(json)
if (json.success == "false") {
$.messager.alert("系统提示", json.msg);
return;
} else {
alert(json.msg);
$("#dlg").dialog("close");
$("#dg").datagrid("reload");
window.location.reload();
}
}
});
}
后端实现
由于客户端表单不是普通的表单,而是martipart/form-data类型的,所有不能通过request请求获取文件,需要通过流实现。
Servlet3.0提供了专门的文件上传 API。HttpServletRequest的getPart()方法可以完成单个文件上传,而getParts()方法可以完成多个文件上传。但这里我不打算使用,而是使用第三方工具
使用第三方工具上传
使用第三方工具,可以锻炼使用其他技术的能力,因为要使用它 ,就需要阅读文档
可以完成上传功能的第三方工具很多,但比较著名的是Apache 的 FileUpload 工具。该工具可以Apache 的官网上下载。Apache 的官网为: http://apache.org
FileUpload工具下载
FileUpload工具存放在Apacher的 Commons 中,所以需要在Commons下载
IO包下载
进一步跟踪该Jar包的信息,会看到如下注意:该版本需要依赖于Apache的Commons下的IO2.2的包。
官网用户向导
打开Apache官网的文件上传主页的用户向导User guide,其中就有使用FileUpload 工具实现文件上传的示例。
代码实现基本上传
首先需要在项目的webapp下新建一个目录 upload,用于保存上传的文件。
然后在controller层的user包下创建AllRegisterServlet.java,下面给出文件上传主要代码实现
try {
if (!ServletFileUpload.isMultipartContent(request)) {
throw new RuntimeException("该请求不能完成文件上传");
}
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
for (FileItem item : fileItems) {
if(item.isFormField()) {
String fieldName = item.getFieldName();
String fieldValue = item.getString();
System.out.println(fieldName + " : " + fieldValue);
} else {
String fileName = item.getName();
InputStream is = item.getInputStream();
String path = this.getServletContext().getRealPath("/upload");
File desFile = new File(path, fileName);
registerFilePath = desFile.getPath();
FileOutputStream fos = new FileOutputStream(desFile);
byte[] bytes = new byte[1024];
int len = -1;
while((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fos.close();
is.close();
}
}
}catch (FileUploadException e) {
e.printStackTrace();
}
上面代码只是解决文件上传功能,但还存在如下问题
- 当用户从表单中提交的普通参数包含中文字符时,会出现乱码问题。
- 当上传文件的文件名包含中文时,上传到服务器的文件名会出现乱码。
- 不同的浏览器,向服务器上传的文件名是不同的,即 Fileltem的getName()方法获取到的文件名是不同的。例如,用户从客户端上传了D:\abc\xxx.jpg文件,火狐浏览器上传的文件名为xxx.jpg,而IE浏览器上传的文件名为D:\abc\xxx.jpg。
- 不同的用户若提交了相同的文件名的文件,后面的用户的文件将无法上传。
解决这些问题的思路:
解决普通参数的中文乱码问题,只需使用Fileltem 的带参getString(String Encoding)方法获取参数名即可。
上传文件名的中文乱码问题,需要通过ServletFileUpload的方法setHeadEncoding()指定上传文件请求头部编码的方式解决。不过,需要注意的是,该设置方式不会改变普通参数请求头部的编码。
为了解决浏览器向服务器发送文件名不同这个问题,需要使用string的substring()方法截取出文件名。因为文件名一定是最后一个"\"后面部分。
对于相同文件名的上传问题,只需要使保存在服务器端的文件名称唯一即可。例如,为原始文件名前添加一个当前系统时间System.currentTimeMillis()
修改后的代码如下
完成到这里,基本的功能都实现了,但还是可以继续优化到最优的,下面进行介绍
无论是 Windows系统、Linux系统,还是其它系统,其目录中所包含的文件数量是有上限的。
所以对于上传的文件,应该分目录进行管理。若文件不是太多,可以在 upload 下按照yyyyMMdd日期格式再建一级子目录。若文件较多,则可按照年、月、日创建多级子目录。这样,即方便管理,又不会超出目录的文件数量上限。
下面按照yyyyMMdd日期格式进行优化,优化后代码如下
至此,文件上传就实现了,之后就是解析上传的文件数据进行注册
也就是说servlet除了处理用户提交的文件还需要做下面三件事
- 通过调用业务方法提取用户上传的文件里所有用户信息
- 获取到所有用户信息后需要遍历,然后调用业务方法检查用户名是否存在,若不存在,执行第三步
- 调用业务方法注册用户
主要代码如下
UserServiceImpl userServiceImpl = new UserServiceImpl();
ArrayList<User> listUser = new ArrayList<User>();
try {
listUser = userServiceImpl.getAllStudent(registerFilePath);
} catch (SQLException e) {
e.printStackTrace();
}
int number = 0;
if (listUser != null) {
for (int i = 0; i < listUser.size(); i++) {
User user = listUser.get(i);
String userId = user.getUserId();
int count = 0;
try {
count = userServiceImpl.checkIdRepeated(userId);
number++;
} catch (SQLException e) {
e.printStackTrace();
}
if (count > 0) {
System.out.println("已存在:" + user.getUserId());
} else {
try {
userServiceImpl.register(user);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("success", "true");
map.put("msg", "成功导入" + number + "条记录");
result = JSON.toJSONString(map);
map.clear();
if (result != null) {
PrintWriter out = response.getWriter();
out.write(result);
}
}
上面用到了提取文件获取所有学生信息的业务方法,也就是需要解析用户上传的文件
在service层的UserService接口中添加提取文件获取所有学生信息的抽象方法,如下
public ArrayList<User> getAllStudent(String registerFilePath) throws SQLException;
}
在service层的实现类UserServiceImpl中重写接口方法getAllRegister,如下
@Override
public ArrayList<User> getAllStudent(String registerFilePath) throws SQLException {
ArrayList<User> listUser = userDao.analyzeFile(registerFilePath);
return listUser;
}
service层只是调用dao层,也就是具体的底层操作,即解析文件获取学生信息是dao层完成的,而service层只是提现业务功能
在dao层的UserDao接口中添加解析文件获取所有学生的抽象方法,如下
public ArrayList<User> analyzeFile(String registerFilePath) throws SQLException;
在dao层的实现类UserDaoImpl中重写接口方法analyzeFile,如下
@Override
public ArrayList<User> analyzeFile(String registerFilePath) throws SQLException {
ArrayList<User> listUser = new ArrayList<User>();
int i = 0;
Sheet sheet;
Workbook book;
Cell cell1, cell2, cell3, cell4, cell5, cell6, cell7;
try {
book = Workbook.getWorkbook(new File(registerFilePath));
sheet = book.getSheet(0);
int col = sheet.getColumns();
int row = sheet.getRows();
i = 0;
if (col > 0 && row > 0) {
while (i < row) {
User user = new User();
if (!sheet.getCell(0, i).getContents().equals("")) {
cell1 = sheet.getCell(0, i);
cell2 = sheet.getCell(1, i);
cell3 = sheet.getCell(2, i);
cell4 = sheet.getCell(3, i);
cell5 = sheet.getCell(4, i);
cell6 = sheet.getCell(5, i);
cell7 = sheet.getCell(6, i);
if (cell1.getContents().equals(""))
{
break;
}
user.setUserId(cell1.getContents());
user.setUserPassword(cell2.getContents());
user.setUserName(cell3.getContents());
user.setUserSex(cell4.getContents());
user.setUserBirthday(cell5.getContents());
user.setUserClass(cell6.getContents());
user.setUserLevel(cell7.getContents());
listUser.add(user);
i++;
}
}
}
book.close();
} catch (Exception e) {
e.printStackTrace();
}
return listUser;
}
底层操作使用了第三方工具库jxl解析excel表格,因为存放数据一般都是使用excel的,这里我就默认excel了,jxl第三方工具jar包可以自行网上下载
到此,批量添加学生的功能就完成了,项目结构如下
启动项目测试
教师管理和学生管理是类似的,就不讲了,下一篇更新资源管理
|