Java进阶学习第二十天——分页与Listener

Posted 鹿天斐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进阶学习第二十天——分页与Listener相关的知识,希望对你有一定的参考价值。

文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.05.18 lutianfei none

customer练习(续)

1.添加

  • 问题:id是varchar类型,它的获取问题?

    • UUID工具类来获取.
  • 完成添加操作:

    • 1.在showCustomer.jsp页面上添加一个连接,可以直接访问到添加页面 add.jsp
    • 2.创建add.jsp

      • 1.关于生日的日历组件My97DataPicker
        • 1.导入js,将My97DataPicker文件夹复制到项目根目录WebRoot
          • <script language="javascript" type="text/javascript" src="${pageContext.request.contextPath}/My97DatePicker/WdatePicker.js"></script>
        • 2.在input type=text组件上添加 class,onclick.
          • 客户生日:<input type="text" name="birthday" class="Wdate" onclick="WdatePicker()" readonly="readonly"><br>
        • 3.修改WdataPicker.js文件,改变初始显示时间。
          • startData后面按照格式填入初始时间
      • 2.关于id问题
        • 使用UUID获取
    • 3.创建CustomerAddServlet完成添加操作

      • 1.得到所有请求参数封装到Customer对象
        • 注意:1.编码问题
          • 2.我们使用BeanUtils,注意Date类型转换问题
          • 3.要手动封装id.
      • 2.调用service完成添加操作


2.批量删除

  • 1.完成页面上全选 与全不选操作
    function change(){
        //1.得到id为main的这个checkbox
        var main=document.getElementById("main");

        var flag=main.checked;

        //2.得到所有name=ck的checkbox
        var cks=document.getElementsByName("ck");

        //3.将cks中所有的checkbox的checked值设置为flag
        for(var i=0;i<cks.length;i++){
            cks[i].checked=flag;
        }
    }


  • 2.完成批量删除

    • 1.页面上怎样将数据提交到服务器端
      • 1.可以创建一个表单,将表单数据提交就可以。
      • 2.直接使用js操作
        • 需要手动拼接出url路径
    • 2.在服务器端怎样批量删除
      • 1.得到所有要删除的id值
        • request.getParameterValues(“ck”);
      • 2.在dao中使用QueryRunner的batch方法
        • batch(sql,Object[][]);
        • 注意:参数二维数据,它代表的是每一条sql的参数。
          • {1,2,3}—–>{{1},{2},{3}}
  • <a href="javascript:void(0)" onclick="sendDel();">

    • 这句话的意思是让href选中的连接失效并跳转到javascript中的sendDel()函数。


3.简单条件查询

技术分享

  • 1 . 在showCustomer.jsp页面上完成
    <div align="center">
        <form>
        <select name="s">
            <option>请选择条件</option>
            <option value="name">按姓名查询</option>
            <option value="cellphone">按手机号查询</option>
            <option value="description">按描述查询</option>
        </select>
        <input type="text" name="msg">
        <input type="submit" value="查询">
        </form>
    </div>
  • 问题: select的名称叫什么?每一个option的值是什么?

    • select可以任意起名。
    • option的value名称需要与customer表中的字段名称对应。
  • 2 . 创建CustomerSimpleSelectServlet完成条件查询

    • 注意sql语句问题:
      • String sql="select * from customer where "+field+" like ?";
      • 一旦使用就相当于加了单引号‘’


分页查询

  • 分页就是将数据以多页去展示,使用分页可以提高客户的感受。

分页分类

  • 1.物理分页

    • 只从数据库中查询出当前页的数据。
    • 优点:不占用很多内存
    • 缺点:效率比较低
  • 2.逻辑分页

    • 从数据库中将所有记录查询出业,存储到内存中,要想展示当前页数据,直接从内存中获取。
    • 优点:效率高
    • 缺点:占用内存比较高
  • 在java开发领域,我们使用的比较多的是物理分页

物理分页的实现
  • 1.直接使用jdbc完成
    • 使用滚动结果集。
      • 优点:跨数据库。
      • 缺点:性能低。
  • 2.使用数据库本身提供的分页操作.
    • 会使用每一个数据库特定的分页函数
      • 优点:性能高
      • 缺点:不能跨数据库。
      • 分页命令关键字:
        • mysql:limit
        • sqlservlet:top
        • oracle:rownum
mysql中使用limit进行分页
  • select * from 表 limit m,n;
    • m:代表的是从第几条开始 注意:它是从0开始记录.
    • n:代表查询几条记录.
  • 示例:分页池,每页显示6条,要查询第2页的数据
    • select * from 表 limit (页码-1)*每页条数,每页条数;

分页分析及代码实现

  • 1.页码 : 默认第一页
  • 2.每页条数 : 人为定义
  • 3.总条数 : select count(*) from 表
  • 4.总页数 : 总页数=Math.ceil(总条数*1.0/每页条数);
  • 5.当前页的数据 select * from 表 limit (页码-1)*每页条数,每页条数;


分页代码实现
  • 1.在success.jsp页面上

    • <a href="${pageContext.request.contextPath}/findAllByPage">查看所有客户信息(分页展示)</a><br>
  • 2.创建CustomerFindAllByPageServlet完成分页

    • 问题:要向页面携带的数据有很多,不仅是要展示的数据,例如:页码,总页数等,都需要携带到页面上,怎样处理?
      • 解决方案:可以创建一个分页Bean,在这个Bean中封装所有关于分页相关的数据.
    private int pageNum; // 页码
    private int currentPage; // 每页条数
    private int totalPage; // 总页数
    private int totalCount; // 总条数
    private List<Customer> cs; // 每页数据


  • 3.在showCustomerByPage.jsp页面上添加
    <a href="/day20_1/findAllByPage?pageNum=1">首页</a>&nbsp;&nbsp;&nbsp;
    <a href="/day20_1/findAllByPage?pageNum=${pb.pageNum-1}">上一页</a>&nbsp;&nbsp;&nbsp;
    <a href="/day20_1/findAllByPage?pageNum=${pb.pageNum+1 }">下一页</a>&nbsp;&nbsp;&nbsp;
    <a href="/day20_1/findAllByPage?pageNum=${pb.totalPage }">尾页</a>&nbsp;&nbsp;&nbsp;
* 在CustomerFindAllByPageServlet中处理请求参数 pageNum
        int pageNum = 1;
        String _pageNum = request.getParameter("pageNum");
        if (_pageNum != null) {
            pageNum = Integer.parseInt(_pageNum);
        }
  • 问题:怎样控制上一页,下一页。
    条件判断就可以解决.
    <c:if test="${pb.pageNum==1}">
        上一页&nbsp;&nbsp;&nbsp;
    </c:if>
    <c:if test="${pb.pageNum!=1}">
        <a href="/day20_1/findAllByPage?pageNum=${pb.pageNum-1}">上一页</a>&nbsp;&nbsp;&nbsp;
    </c:if>

    <c:if test="${pb.pageNum==pb.totalPage}">
        下一页&nbsp;&nbsp;&nbsp;
    </c:if>
    <c:if test="${pb.pageNum!=pb.totalPage}">
        <a href="/day20_1/findAllByPage?pageNum=${pb.pageNum+1 }">下一页</a>&nbsp;&nbsp;&nbsp;
    </c:if>


分页扩展

  • 1.设定每页显示条数
    • 1.在showCustomerByPage.jsp页面上添加一个<select>
    <select name="currentPage" onchange="changeCurrentPage(this.value);">
        <option>--请选择每页条数--</option>
        <option value="5">5</option>
        <option value="10">10</option>
        <option value="20">20</option>
    </select>

    function changeCurrentPage(value){        
        location.href="/day20_1/findAllByPage?currentPage="+value;
};    
* 2.在首页,上一页,下一页,尾页的连接上也要添加每页显示条数。
    * `<a href="/day20_1/findAllByPage?pageNum=1&currentPage=${pb.currentPage}">首页</a>`


  • 2.关于页码显示
    <c:forEach begin="1" end="${pb.totalPage}" var="n" step="1">
        <a href="/day20_1/findAllByPage?pageNum=${n}&currentPage=${pb.currentPage}">第${n}页</a>&nbsp;&nbsp;
    </c:forEach>
  • 问题:如果页码比较多怎样处理?
    • 可以限定页码数,例如:前5后4。
    • 这样做,页面的判断条件比较多,可以使用自定义标签。
    • 可以在自定义标签中通过java代码来解决判断操作。如果直接在页面上,使用<c:if>代码太乱。


监听器

  • 监听事件的发生需要如下因素:

    • 1.事件 ActionEvent
    • 2.事件源 JButton
    • 3.监听器 ActionListener
    • 4.注册监听 addActionListener();
  • 监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

  • 在javaweb中有什么监听器,有什么作用?

    • javaweb中的监听器,主要用于监听javaweb中常用对象
      • request(HttpServletRequest)
      • session(HttpSession)
      • application(ServletContext)
    • 监听器的作用
      • 1.对象的创建与销毁
      • 2.对象的属性变化
      • 3.session绑定javaBean.


  • 1.监听创建与销毁

    • HttpServletRequest
      • 监听器:ServletRequestListener可以监听request对象的创建销毁
    • HttpSession
      • 监听器:HttpSessionListener可以监听session对象的创建销毁
    • ServletContext
      • 监听器:ServletContextListener可以监听application对象的创建销毁
  • 2.监听web对象的属性变化

    • HttpServletRequest属性变化
      • 监听器:ServletRequestAttributeListener监听request对象的属性变化
    • HttpSession属性变化
      • 监听器:HttpSessionAttributeListener 监听session对象的属性变化
    • ServletContext属性变化
      • 监听器:ServletContextAttributeListener监听application对象的属性变化。


编写监听器

  • 和编写其它事件监听器一样,编写servlet监听器也需要实现一个特定的接口,并针对相应动作覆盖接口中的相应方法。
  • 和其它事件监听器略有不同的是,servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用<listener>标签配置好监听器,web容器就会自动把监听器注册到事件源中。
  • 一个 web.xml 文件中可以配置多个 Servlet 事件监听器,web 服务器按照它们在 web.xml 文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。
创建监听器步骤
  • 1.创建一个类,去实现指定的监听器接口.
  • 2.重写接口中方法。
  • 3.在web.xml文件中配置注册监听
    <!-- 监听器案例-->
    <listener>
        <listener-class>cn.itcast.listener.demo.MyServletContextListener</listener-class>
    </listener>


  • 具体实现
  • 1.监听application对象的创建与销毁.

    • 问题:application对象什么时候创建,什么时候销毁的?
      • application对象是服务器启动时创建,服务器关闭时销毁。
  • 2.监听session对象创建与销毁

    • 问题:session对象什么时候创建,什么时候销毁?
      • session对象创建:
        • reqeust.getSession();它是用于获取session
          • 是否创建,分以下几种情况:
            • 1.请求中如果没有jsessionid,那么就是创建session对象。
            • 2.如果请求头中有jsessionid值:
              • 1.如果在服务器端,有一个session的id值与其一样,不创建,直接使用。
              • 2.如果在服务器端,没有这个session的id值,那么会创建。
      • session对象销毁:
        • 1.默认超时 30 分钟
        • 2.设置session超时时间
          • setMaxInactiveInterval(int interval)
        • 3.invalidate()手动销毁
        • 4.关闭服务器


  • 3.监听request对象创建与销毁
    • 问题:request对象什么时候创建,什么时候销毁?
      • 请求发生,request对象创建,响应产生request对象销毁。


ServletContext监听器

  • ServletContextListener 接口用于监听 ServletContext 对象的创建和销毁事件。
  • 当 ServletContext 对象被创建时,激发contextInitialized (ServletContextEvent sce)方法
  • 当 ServletContext 对象被销毁时,激发contextDestroyed(ServletContextEvent sce)方法。
  • 提问,servletContext域对象何时创建和销毁:

    • 创建:服务器启动针对每一个web应用创建servletcontext
    • 销毁:服务器关闭前先关闭代表每一个web应用的servletContext
  • 示例1 简单任务调度Timer与TimerTask使用

Servlet监听器

  • 在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为 ServletContext, HttpSessionServletRequest 这三个域对象。

  • Servlet规范针对这三个对象上的操作,又把这多种类型的监听器划分为三种类型。

    • 监听三个域对象创建销毁的事件监听器
    • 监听域对象中属性增加和删除的事件监听器
    • 监听绑定到 HttpSession 域中的某个对象的状态的事件监听器。(查看API文档)
  • 在javaweb中servlet规范中定义了三种技术 : servlet Listener Filter


HttpSession监听器

  • HttpSessionListener接口用于监听HttpSession的创建销毁
    • 创建一个Session时,sessionCreated(HttpSessionEvent se) 方法将会被调用。
    • 销毁一个Session时,sessionDestroyed (HttpSessionEvent se) 方法将会被调用。


ServletRequest监听器

  • ServletRequestListener 接口用于监听ServletRequest 对象的创建和销毁。

    • Request 对象被创建时,监听器的requestInitialized方法将会被调用。
    • Request对象被销毁时,监听器的requestDestroyed方法将会被调用。
  • 当向被监听器对象中增加一个属性时,web容器就调用事件监听器的 attributeAdded 方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象。

    • 各个域属性监听器中的完整语法定义为:
      • public void attributeAdded(ServletContextAttributeEvent scae)
      • public void attributeAdded (HttpSessionBindingEvent hsbe)
      • public void attributeAdded(ServletRequestAttributeEvent srae)

监听三个域的属性变化

  • Servlet规范定义了监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器。
  • 这三个监听器接口分别是ServletContextAttributeListener, HttpSessionAttributeListener ServletRequestAttributeListener
  • 这三个接口中都定义了三个方法来处理被监听对象中的属性的增加删除替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
  • 当向被监听器对象中增加一个属性时,web容器就调用事件监听器的 attributeAdded 方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象
  • 各个域属性监听器中的完整语法定义为:

    • public void attributeAdded(ServletContextAttributeEvent scae)
    • public void attributeAdded (HttpSessionBindingEvent hsbe)
    • public void attributeAdded(ServletRequestAttributeEvent srae)
  • 当**删除被监听对象中的一个属性时,web 容器调用事件监听器的这个方法进行相应

  • 各个**域属性监听器中的完整语法定义为:

    • public void attributeRemoved(ServletContextAttributeEvent scae)
    • public void attributeRemoved (HttpSessionBindingEvent hsbe)
    • public void attributeRemoved (ServletRequestAttributeEvent srae)
  • 当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的这个方法进行相应

  • 各个域属性监听器中的完整语法定义为:
    • public void attributeReplaced(ServletContextAttributeEvent scae)
    • public void attributeReplaced (HttpSessionBindingEvent hsbe)
    • public void attributeReplaced (ServletRequestAttributeEvent srae)


  • 演示监听session的属性变化
    public class MySessionAttributeListener implements HttpSessionAttributeListener {

        public void attributeAdded(HttpSessionBindingEvent arg0) {

            // arg0.getSession(); 获取事件源,也就是获取session对象.
            System.out.println(arg0.getName());
            System.out.println(arg0.getValue());
            System.out.println("向session中添加属性");
        }

        public void attributeRemoved(HttpSessionBindingEvent arg0) {
            System.out.println("从session中移除属性");
        }

        public void attributeReplaced(HttpSessionBindingEvent arg0) {
            System.out.println("将session中的属性修改");
        }

    }


  • 问题:在监听器中是否可以得到属性值?

    • 常识:在java的监听机制中,是可以在监听器中获取事件源的。
    • 我们在开发中,如果有到了事件触发机制,那么一般情况下,都可以使用
    • 方法的参数(事件对象)来获取想要的信息。
  • 思考一个问题:这些监听器在开发中有什么用?

    • 在主流中应用比较少,但是可以完成一些性能监试操作。


监听器案例

  • 功能:扫描session对象在指定时间内没有使用,人为销毁。

  • 分析:

    • 1.怎样知识session多长时间没有使用?
      • 当前时间-最后使用时间(public long getLastAccessedTime()
    • 2.什么时候开始扫描,扫描多长时间?
      • 可以使用Timer完成
  • 完成定时扫描session,如果超时没有使用,销毁案例:
    1.要将所有的session对象得到,保存到集合中。
    1.创建一个监听器 ServletContextListener,它服务器启动时,创建一个集合保存到ServletContext域。
    2.创建一个监听器 HttpSessionListener,当创建一个session时,就从ServletContext域中获取集合,将session对象储存到集合中。

    2.定时扫描

    问题:
        1.session超时,不能只销毁session,还要从集合中移除。
    
        2.我们的操作,它是多线程的,要考虑集合的同步问题。
            1.集合需要是线程安全的。
            2.需要使用迭代器进行遍历。
    


Session绑定监听器

  • 保存在Session域中的对象可以有多种状态:

    • 绑定到 Session 中;
    • 从 Session 域中解除绑定;
    • 随 Session 对象持久化到一个存储设备中(钝化);
    • 随 Session 对象从一个存储设备中恢复(活化);
  • Servlet 规范中定义了两个特殊的监听器接口来帮助JavaBean对象了解自己在 Session域中的这些状态。

    • HttpSessionBindingListener接口
    • HttpSessionActivationListener接口
    • 实现这两个接口的类不需要web.xml 文件中进行注册
  • 实现了HttpSessionBindingListener接口的 JavaBean 对象可以感知自己被绑定到 Session 中和从 Session中删除的事件

    • 当对象被绑定到 HttpSession 对象中时,web服务器调用该对象的 void valueBound(HttpSessionBindingEvent event) 方法
    • 当对象从 HttpSession 对象中解除绑定时,web服务器调用该对象的 void valueUnbound(HttpSessionBindingEvent event)方法
  • 实现了HttpSessionActivationListener接口的 JavaBean对象可以感知自己被活化钝化的事件

    • 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化之前,web 服务器调用如下方法sessionWillPassivate(HttpSessionBindingEvent event) 方法
    • 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化之后,web 服务器调用该对象的 void sessionDidActive(HttpSessionBindingEvent event)方法
    • 钝化—>将session中的javaBean保存到文件中.
    • 活化—>从文件中将javaBean直接获取。
  • 需要创建一个配置文件context.xml

    • 这个文件保存到META-INF目录下.
    <Context>
    <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
    <Store className="org.apache.catalina.session.FileStore" directory="it315"/>
    </Manager>
    </Context>


  • 这两个监听器特点;
    • 1.它们是由javaBean实现。
    • 2.它们不需要在web.xml文件中配置。








































































以上是关于Java进阶学习第二十天——分页与Listener的主要内容,如果未能解决你的问题,请参考以下文章

Python入门自学进阶-Web框架——25DjangoAdmin项目应用-分页与过滤

Python入门自学进阶-Web框架——25DjangoAdmin项目应用-分页与过滤

mysql进阶之细谈索引分页与慢日志

java学习--基础知识进阶第十天--笔记

ES深度分页与批量操作

Java进阶学习第二十二天——上传与下载