手记

JSP+Servlet培训班作业管理系统[15] -分页(以人员管理为例)

先展示下分页成果:


刚开始接触炸窝(Java)的时候,猫哥比较怵分页,感觉很麻烦。其实只要理解了,还是相当简单的。怎么理解呢,自己动手实现一次(一次就够够的了,但找别人的代码复制粘贴就不好了,就不算自己动手)。如果自己动手都不知道该从何下手咋办,没事,这篇就是说怎么分页的。

第一,如果某个页面,比如显示人员列表的页面,需要分页。如果后台没有收到跟页码相关的参数,那默认肯定要显示第一页。如果这个都不理解,猫哥Game Over!

第二,那么要实现分页,后台只需要前台告诉自己,客户您想看第几页就行了。为啥?此处用精妙的小学数学知识演示一下哈:

现在有整数a,b,c,d
a:前台,也就是浏览器用户想看的页码,也就是想看第a页。
b:后台(网站设计者)想每页显示的人员个数
c:系统中人员总数 c
d:最大页码数  d=c/b+((c%b)>0?1:0),此处解释下d为啥小学生会计算,如果c除以b没有余数,那么d=c/b,如果c除以b有余数,d=c/b+1
最后,每页显示的人员是从(a-1)*b开始的连续b个

原理解释完了,具体实现如下:

step1,Constant代码如下,需注意2点,1是点击人员管理菜单后会调用/HomeworkSystem/ActionServlet?method=${menu[1]}&entityType=${menu[2]},注意此处人员管理对应的method=view、entityType=User。2是猫哥为了演示方便将所有实体列表显示页面每页显示实体个数都初始化为5。

package util;
import java.util.HashMap;
public class Constant {//保存常量信息
    //roleMenu用于保存角色及对应的菜单信息
    public static HashMap<String,String[][]> RoleMenu=new HashMap<String,String[][]>();
    //pageSize用于保存不同实体列表页面显示实体个数信息(每页多少个)
    public static HashMap<String,Integer> PageSize=new HashMap<String,Integer>();
    //使用static代码块对roleMenu进行初始化
    static{
        //注意,二位数组中的每一组表示一个菜单的信息,又通过map建立了角色名和菜单直接的对应关系
        RoleMenu.put("校长", new String[][]{
                {"人员管理","view","User"},//由具体的地址,变为抽象的参数
                {"课程管理","view","Course"}
        });
        RoleMenu.put("教师", new String[][]{});
        RoleMenu.put("学生", new String[][]{});
        //初始化页面列表个数
        PageSize.put("Course", 5);
        PageSize.put("Job", 5);
        PageSize.put("Lesson", 5);
        PageSize.put("Role", 5);
        PageSize.put("User", 5);
        PageSize.put("Work", 5);
    }   
}

step2,点击菜单后跳转ActionServlet代码如下,

public class ActionServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doPost(request, response);//doGet与doPost一样处理
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //输入输出格式设置
        response.setContentType("text/html");
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        //根据request用户输入信息创建不同的ActionContext(Action上下文)
        ActionContext context=ActionController.assemblyActionContext(request);
        //根据不同的ActionContext创建不懂的action动作
        Action action=ActionController.dispatchAction(context);
        try {
            context=action.execute();//执行动作并返回结果
        } catch (MyException ex) {//如果有异常,跳转异常提示页面
            request.setAttribute("tipInfo", ex.getInfo());
            request.getRequestDispatcher("/tip.jsp").forward(request,response);
        }
        //设置返回页面
        request.setAttribute("actionUrl",context.getActionUrl());
        //取上下文中的返回值     
        Map<String,Object> map=context.getOutputParams();
        if(map!=null){
            Iterator iter = map.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                Object key = entry.getKey();
                Object val = entry.getValue();
                if(key.toString().startsWith("session")){
                    request.getSession().setAttribute(key.toString(), val);
                }else{
                    request.setAttribute(key.toString(), val);
                }
            }
        }
        //跳转到index.jsp主页面,注意 actionUrl指向页面显示在index.jsp右边内容区域
        request.getRequestDispatcher("/index.jsp").forward(request,response);
    }
}

step3,在ActionController中新增路由规则,此处直接给出人员管理增删改查及用户登录规则实现:

package servlet;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import factory.EntityFactory;
import action.*;
import action.support.Action;
import action.support.ActionContext;
/**
 * 实质的控制器
 * @author 猫哥
 * @date 2017.2.11
 * 一定注意该类是整个控制逻辑的核心,每当有新的Action来了,需要从本类进行类似“注册”的动作,而且必须保证
 * createAction与assemblyActionContext正确的呼应(对应)关系
 */
public class ActionController {
    /*
    assembly装配的意思,装配ActionContext即装配动作的上下文,上下文的意思就是环境
    一定注意本方法不管如何执行,只关心需要执行时候需要哪些参数
    */
    public static ActionContext assemblyActionContext(HttpServletRequest request){
        ActionContext context=new ActionContext();
        //装配两个必备参数
        context.setOperationType(request.getParameter("method"));
        context.setEntityType(request.getParameter("entityType"));
        //剩下的就是根据需要装配了
        //------------------------------------------------------------------delete
        if(context.getOperationType().equals("delete")){
            //装配delete方法的上下文,可以想到无论delete什么实体,都只需要实体编号,所以先装配实体编号
            //在装配实体编号时候,前后台遵循一个约定就是命名为entityId
            String entityId=request.getParameter("entityId");
            context.setEntityId(Integer.parseInt(entityId));
        //------------------------------------------------------------------view
        }else if(context.getOperationType().equals("view")){
            //将page传递给action
            context.setPage(request.getParameter("page"));
        }
        //------------------------------------------------------------------add
        else if(context.getOperationType().equals("add")){
            //add需要携带啥参数呢,对于人员管理来说,本来可能需要携带角色列表(页面上要显示角色列表信息嘛)
            //但是由于角色列表是固定,在网页直接写死,不用从数据库中查询,所以此时依然不携带参数
        }
        //------------------------------------------------------------------edit
        else if(context.getOperationType().equals("edit")){
            //点击编辑后,需要显示被编辑人的信息,所以edit要携带id
            String entityId=request.getParameter("entityId");
            context.setEntityId(Integer.parseInt(entityId));
        }
        //------------------------------------------------------------------save
        else if(context.getOperationType().equals("save")){
            //注意,点击保存后,不同的实体需要携带不同的参数列表,所以采用createEntityFromRequest来创建实体
            Object entity=EntityFactory.createEntityFromRequest(context.getEntityType(), request);
            Map<String,Object> map=new HashMap<String,Object>();
            map.put("waitSaveEntity", entity);
            context.setInputParams(map);

            String id=request.getParameter("entityId");
            if(id==null||"".equals(id)){
                context.setEntityId(-1);
            }else{
                context.setEntityId(Integer.parseInt(id));
            }

        }
        //------------------------------------------------------------------other
        else if(context.getOperationType().equals("login")){
            //登录时间,需要携带用户输入的用户名、密码
            Map<String,Object> map=new HashMap<String,Object>();
            map.put("userId", request.getParameter("userId"));
            map.put("userPassword", request.getParameter("userPassword"));
            context.setInputParams(map);
        }
        return context;
    }

    /*
    dispatch的意思是调度,分派
     一定注意本方法只关心将context中请求派给哪个Action处理
    为了保证呼应,可先直接将上面if段拷贝,然后修改内容
    */ 
    public static Action dispatchAction(ActionContext context){
        //------------------------------------------------------------------delete
        if(context.getOperationType().equals("delete")){
            return new DeleteAction(context);
        //------------------------------------------------------------------view
        }else if(context.getOperationType().equals("view")){
            return new ViewAction(context);
        }
        //------------------------------------------------------------------add
        else if(context.getOperationType().equals("add")){
            return new AddAction(context);
        }
        //------------------------------------------------------------------edit
        else if(context.getOperationType().equals("edit")){
            return new EditAction(context);
        }
        //------------------------------------------------------------------save
        else if(context.getOperationType().equals("save")){
            return new SaveAction(context);
        }
        //------------------------------------------------------------------other
        else if(context.getOperationType().equals("login")){
            return new LoginAction(context);
        }
        return null;
    }
}

step4,可见处理事件的Action为ViewAction,代码如下:

package action;
import inter.IOperation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import util.Constant;
import action.support.Action;
import action.support.ActionContext;
import exception.MyException;
import factory.OperationFactory;
/***
 * 动作:查看用户列表
 * @author 猫哥
 * @date 2017.2.9
 * @modify 分页 by 猫哥
 */
public class ViewAction extends Action{
    public ViewAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        //获取数据库操作对象
        IOperation oper=OperationFactory.createOperation(context.getEntityType());
        //处理分页
        String input_page=context.getPage();
        int page,size,offset,total,maxPage;//分别代表要显示的页码,每页显示个数,偏移数,总个数,最大页数
        total=oper.selectCount();
        size=Constant.PageSize.get(context.getEntityType());
        int temp1=total/size;
        int temp2=total%size;
        maxPage=total/size+((total%size)>0?1:0);
        if(input_page==null||"".equals(input_page))
            page=1;
        else
            page=Integer.parseInt(input_page);
        if(page<1)//第一页时点击上一页
            page=1;
        else if(page>maxPage)//最后一页时点击下一页
            page=maxPage;
        offset=(page-1)*size;
        //处理返回值
        List result=oper.selectPage(offset, size);
        Map<String,Object> back=new HashMap<String,Object>();
        back.put(context.getEntityType().toLowerCase()+"s",result);
        back.put("currentPage", page);
        back.put("maxPage", maxPage);
        context.setOutputParams(back);
        context.setActionUrl(`context.getEntityType().toLowerCase()+"Manage.jsp"`); 
        return context;
    }
}

step5,ViewAction处理完毕后跳转的actionUser为context.getEntityType().toLowerCase()+"Manage.jsp",也就是userManage.jsp,其代码为:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用c:标签需要添加本行代码 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>  
    <title>userManage.jsp</title>
    <link href="css/content.css" type="text/css" rel="stylesheet"/>
    <link href="css/table.css" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <div id="content_top">
        人员管理
    </div><!-- user_top end -->
    <div id="content_mid">
        <table class="table_theme1">
            <thead>
                <th>人员编码</th>
                <th>姓名</th>
                <th>角色</th>
                <th>操作</th>
                <th>操作</th>
            </thead>
            <c:forEach items="${users}" var="item">
                <tr>
                    <td>${item.userId}</td>
                    <td>${item.userName}</td>
                    <td>${item.userRole.roleName}</td>
                    <td><a href="/HomeworkSystem/ActionServlet?method=edit&entityType=User&entityId=${item.userId}">编辑</a></td>
                    <td><a href="/HomeworkSystem/ActionServlet?method=delete&entityType=User&entityId=${item.userId}">删除</a></td>
                </tr>
            </c:forEach>    
            <tr><td colspan="5">共${maxPage}页  当前是第${currentPage}页   <a href="/HomeworkSystem/ActionServlet?method=view&entityType=User&page=${currentPage-1}">上一页</a>  <a href="/HomeworkSystem/ActionServlet?method=view&entityType=User&page=${currentPage+1}">下一页</a></td></tr>
        </table>
    </div><!-- user_mid end -->
    <div id="content_bottom">
        <a href="/HomeworkSystem/ActionServlet?method=add&entityType=User">新增</a>
    </div><!-- "user_bottom" end -->
  </body>
</html>

step6,userManage.jsp页面中包含了修改、删除、新增、请求新页码对应的人员显示页等链接,同样点击这些链接后交由ActionServlet-ActionController-Action派生类处理链。
因为原理已经详述过,此处不再作具体解释直接粘贴源码如下:

/***
 * 动作:点击新增按钮后对应动作,直接跳转对应实体更新页面
 * @author 猫哥
 * @date 2017.2.9
 */
public class AddAction extends Action{
    public AddAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        context.setActionUrl(context.getEntityType().toLowerCase()+"Update.jsp"); 
        return context;
    }
}
/***
 * 动作:删除后对应动作
 * @author 猫哥
 * @date 2017.2.9
 */
public class DeleteAction extends Action{
    public DeleteAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        //按类型获取实体操作类
        IOperation oper=OperationFactory.createOperation(context.getEntityType());
        int affectedCount=oper.deleteById(context.getEntityId());
        if(affectedCount<1){//删除失败咯
            throw new MyException(new Date(),"DeleteAction执行失败,entityType:"+context.getEntityType(),"删除失败");
        }else{//调用对应的更新列表
            context.setOperationType("view");
            Action action=ActionController.dispatchAction(context);
            return action.execute();
        }
    }
}
/***
 * 动作:点击修改按钮后对应动作
 * @author 猫哥
 * @date 2017.2.9
 */
public class EditAction extends Action{
    public EditAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        IOperation oper=OperationFactory.createOperation(context.getEntityType());
        Object entity=oper.selectById(context.getEntityId());
        Map<String,Object> back=new HashMap<String,Object>();
        back.put(context.getEntityType().toLowerCase(),entity);
        context.setOutputParams(back);
        context.setActionUrl(context.getEntityType().toLowerCase()+"Update.jsp"); 
        return context;
    }
}
/***
 * 动作:点击保存按钮后对应动作
 * @author 猫哥
 * @date 2017.2.9
 */
public class SaveAction extends Action{
    public SaveAction(ActionContext context){
        super(context);
    }
    @Override
    public ActionContext execute() throws MyException {
        IOperation oper=OperationFactory.createOperation(context.getEntityType());
        int id=context.getEntityId();
        Object entity=context.getInputParams().get("waitSaveEntity");
        int affectedCount=-1;
        if(id==-1){//添加
            affectedCount=oper.add(entity);
        }else{//修改
            affectedCount=oper.update(entity);
        }
        if(affectedCount<1){//失败咯
            throw new MyException(new Date(),"SaveAction执行失败,entityType:"+context.getEntityType(),"更新失败");
        }else{//更新列表
            context.setOperationType("view");
            Action action=ActionController.dispatchAction(context);
            return action.execute();
        }
    }
}

step7,最后还有userUpdate.jsp页面和修改的IOperation及所有实体操作类源代码:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用c:标签需要添加本行代码 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>  
    <title>userUpdate.jsp</title>
    <link href="css/content.css" type="text/css" rel="stylesheet"/>
    <link href="css/table.css" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <form action="/HomeworkSystem/ActionServlet?method=save&entityType=User" method="post">
        <div id="content_top">
            人员信息更新
        </div><!-- user_top end -->
        <div id="content_mid">
            <table class="table_theme1">
                <tr>
                    <td>姓名:</td>
                    <td>
                        <input type="text" name="userName" value="${user.userName}"/>
                        <input type="hidden" name="hiddenId" value="${user.userId}"/>
                    </td>
                </tr>
                <tr>
                    <td>角色:</td>
                    <td>
                        <select name="userRole"><!-- 编辑情况下,默认显示编辑用户的角色的功能,待后续优化项目时再讲如何实现 -->
                            <option value="1">校长</option>
                            <option value="2">老师</option>
                            <option value="3">学生</option>
                        </select>
                    </td>
                </tr>
            </table>
        </div><!-- user_mid end -->
        <div id="content_bottom">
            <input type="submit" value="保存"></input>
        </div><!-- "user_bottom" end -->
      </form>
  </body>
</html>
package inter;
import java.util.List;
//规范了用于执行对象对应数据库表基本操作的类
public interface IOperation {
    public int selectCount();//获取个数
    public List selectAll();//选取表中所有数据
    public List selectPage(int offset,int size);//分页显示,第一个参数为起始位置(按id排序),第二个参数为每页显示个数
    public Object selectById(int id);//按id获取一条记录
    public int add(Object obj);//添加一条数据
    public int deleteById(int id);//按id删除一条记录
    public int update(Object obj);//按obj对象的信息修改一条记录(以obj的id标记需要修改的记录)
}

因实现IOperation接口的类代码基本一样,此处只放了CourseOperation 。

package operation;
import inter.IOperation;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import database.MySQLHandler;
import entity.*;
import exception.MyException;
public class CourseOperation implements IOperation{
    @Override
    public int selectCount() {
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        int re=0;
        try {
            //此处不要写select *,因为数据库将*转换为该表所有列名肯定需要浪费时间
            rs=hand.query("select count(course_id) as count from system_course");
            while(rs.next()){
                re=rs.getInt("count");
            }
            hand.sayGoodbye();
            return re;
        } catch (Exception ex) {
            //对于数据库操作层面的异常,此时不予以向外抛出,记录在日志中分析即可
            //在设计的时候就要明确,什么类型异常要外抛,什么异常不抛出只记录
            new MyException(new Date(),ex.getMessage(),"CourseOperation.selectCount异常");
            return 0;//注意null和new Course()并不同!
        }
    }
    @Override
    public Object selectById(int id) {
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        Course one=new Course();//如果查询内容为空,则通过one.getCourseId()==0来判断即可
        try {
            //此处不要写select *,因为数据库将*转换为该表所有列名肯定需要浪费时间
            rs=hand.query("select Course_id,Course_name,user_id,user_name from "
                    +"system_Course c,system_user u where c.Course_id='"+id+"' and c.Course_user=u.user_id");
            while(rs.next()){
                one.setCourseId(rs.getInt("Course_id"));
                one.setCourseName(rs.getString("Course_name"));     
                User user=new User();
                user.setUserId(rs.getInt("user_id"));
                user.setUserName(rs.getString("user_name"));
                one.setCourseUser(user);
            }
            hand.sayGoodbye();
            return one;
        } catch (Exception ex) {
            //对于数据库操作层面的异常,此时不予以向外抛出,记录在日志中分析即可
            //在设计的时候就要明确,什么类型异常要外抛,什么异常不抛出只记录
            new MyException(new Date(),ex.getMessage(),"CourseOperation.selectById异常");
            return null;//注意null和new Course()并不同!
        }
    }
    @Override
    public List selectAll() {//注意返回值null和list.size()==0的区别
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        ArrayList<Course> list=new ArrayList<Course>();//返回值
        try {
            rs=hand.query("select Course_id,Course_name,user_id,user_name from "
                    +"system_Course c,system_user u where c.Course_user=u.user_id");
            while(rs.next()){
                Course one=new Course();//返回值中的一个
                one.setCourseId(rs.getInt("Course_id"));
                one.setCourseName(rs.getString("Course_name"));     
                User user=new User();
                user.setUserId(rs.getInt("user_id"));
                user.setUserName(rs.getString("user_name"));
                one.setCourseUser(user);
                list.add(one);//添加到列表
            }
            hand.sayGoodbye();//释放资源
            return list;
        } catch (Exception ex) {
            new MyException(new Date(),ex.getMessage(),"CourseOperation.selectAll异常");
            return null;
        }
    }
    @Override
    public List selectPage(int offset, int size) {
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        ArrayList<Course> list=new ArrayList<Course>();//返回值
        try {
            rs=hand.query("select Course_id,Course_name,user_id,user_name from "
                    +" system_Course c,system_user u where c.Course_user=u.user_id "
                    +" order by c.Course_id limit "+offset+","+size);
            while(rs.next()){ 
                Course one=new Course();//返回值中的一个
                one.setCourseId(rs.getInt("Course_id"));
                one.setCourseName(rs.getString("Course_name"));     
                User user=new User();
                user.setUserId(rs.getInt("user_id"));
                user.setUserName(rs.getString("user_name"));
                one.setCourseUser(user);
                list.add(one);//添加到列表
            }
            hand.sayGoodbye();//释放资源
            return list;
        } catch (Exception ex) {
            new MyException(new Date(),ex.getMessage(),"CourseOperation.selectPage异常");
            return null;
        }
    }
    @Override
    public int add(Object obj) {
        Course one=(Course)obj;
        MySQLHandler hand=new MySQLHandler();
        try {
            int re=hand.execute("insert into system_Course(Course_name,Course_user)"
                    +" values('"+one.getCourseName()+"','"+one.getCourseUser().getUserId()+"')");
            hand.sayGoodbye();
            return re;
        } catch (Exception ex) {
            new MyException(new Date(),ex.getMessage(),"CourseOperation.add异常");
            return 0;
        }
    }
    @Override
    public int deleteById(int id) {
        MySQLHandler hand=new MySQLHandler();
        try {
            int re=hand.execute("delete from system_Course where Course_id='"+id+"'");
            hand.sayGoodbye();
            return re;
        } catch (Exception ex) {
            new MyException(new Date(),ex.getMessage(),"CourseOperation.deleteById异常");
            return 0;
        }
    }
    @Override
    public int update(Object obj) {
        Course one=(Course)obj;
        MySQLHandler hand=new MySQLHandler();
        try {
            int re=hand.execute("update system_Course set Course_name='"+one.getCourseName()
                    +"',Course_user='"+one.getCourseUser().getUserId()
                    +"' where Course_id='"+one.getCourseId()+"'");
            hand.sayGoodbye();
            return re;
        } catch (Exception ex) {
            new MyException(new Date(),ex.getMessage(),"CourseOperation.update异常");
            return 0;
        }
    }
}
7人推荐
随时随地看视频
慕课网APP