码迷,mamicode.com
首页 > 数据库 > 详细

JavaWeb-18 (JDBC之分页与监听器listener)

时间:2015-04-03 09:36:42      阅读:274      评论:0      收藏:0      [点我收藏+]

标签:javaweb

JavaWeb-18

JDBC之分页与监听器listener

一、分页

1、分页概述:分页的结果就是要让指定的记录加载到内存

2、原因:

1、人的习惯
2、内存的限度(核心问题)
3、屏幕的限度

3、如何分页:

不同的环境方式不一样

3.1、数据库层面:

select * from acount limit startIndex,size;//只是针对MySql而言(startIndex从0开始,size:共查询多少条记录)
select * from acount limit 0,3; 第一页(1,2,3)
select * from acount limit 3,3; 第二页(4,5,6)

转换到编程上的思想:startIndex: (pageNo-1)*size   (pageNo:第几页)

总记录数:
    select count(*) from 表名

3.2、程序代码上思考

a(思路)、直接发送select * from acount limit 0,3;这样的SQL语言(推荐使用该思想)
ResultSet中存的数据就是指定的记录。

b(思路)、发送一个select * from acount;查询所有的SQL语句(一般不考虑,因为没有解决内存本质问题)
ResultSet 结果集中
在内存中处理结果(只加载前10条)

3.3、程序代码上做分页怎么写?怎么控制?JDBC里怎么实现?

使用思路a的思想:

引入一个JavaBean分页组件:PageBean

分页组件:PageBean.java

//分页组件用于实现封装分页的相关信息
{
    private int pageNo=1;//当前是第几页
    private int pageSize=3;//每页最多显示几条
    private int prep;//上一页
    private int nextp;//下一页
    private int totalPage;//总页数
    private int totalRecordes;//总记录数
    //变量之间是有关联的
    private int startIndex;//代表分页的起始的索引(pageNo-1)*pageSize
    private List records;//当前页的所有记录:需要查询数据库获取变量值
}

生成bean

回顾:el表达式其实是调用bean的get方法。

现在在各个属性的get方法加入if语句不断挖掘变量之间的关系。

eg:

    public int getTotalPage(){
        if(totalRecordes%pageSize==0){
            ....
        }else{
                ...
            }
        return ...;

    }


    public int getPrep(){
        if(pageNo<=){
            ...
        }else{
                prep=pageNo-1;
            }
            return prep;
    }

    public int getNextp(){
        if(pageNo>=getTotalPage()){
            ...
        }else{
                ...
            }
        return nextp;
    }


    public int getStartIndex(){
        ....
        return ...;
    }

实验:项目:day1800pagebean

技术分享

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>ControllerServlet</servlet-name>
    <servlet-class>com.itheima.web.controller.ControllerServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ControllerServlet</servlet-name>
    <url-pattern>/servlet/ControllerServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

AccountDao.java

package com.itheima.dao;

import java.util.List;

import com.itheima.domain.Account;

public interface AccountDao {

    public int getCount();

    public List<Account> findRecordesByPage(int startIndex,int size);
}

AccountDaoImpl.java

package com.itheima.dao.impl;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.utils.C3P0Util;

public class AccountDaoImpl implements AccountDao {
    private QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
    public int getCount() {
        try {
            return ((Long)qr.query("select count(1) from account",new ScalarHandler())).intValue();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public List<Account> findRecordesByPage(int startIndex, int size) {
        try {
            return qr.query("select * from account limit ?,?",new BeanListHandler<Account>(Account.class),startIndex,size);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

}

Account.java

package com.itheima.domain;

import java.io.Serializable;

public class Account implements Serializable {

    private int id;
    private String name ;
    private float money;

    public Account(int id, String name, float money) {
        super();
        this.id = id;
        this.name = name;
        this.money = money;
    }

    public Account() {
        super();
    }


    @Override
    public String toString() {
        return "Account [id=" + id + ", name=" + name + ", money=" + money
                + "]";
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getMoney() {
        return money;
    }
    public void setMoney(float money) {
        this.money = money;
    }
}

AccountServlice.java

package com.itheima.service;

import com.itheima.web.form.PageBean;

public interface AccountService {

    public void findRecordesByPage(PageBean pb);
}

AccountServletImpl.java
package com.itheima.service.impl;

import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.service.AccountService;
import com.itheima.web.form.PageBean;

public class AccountServiceImpl implements AccountService {
    private AccountDao dao = new AccountDaoImpl();
    public void findRecordesByPage(PageBean pb) {
        pb.setTotalRecordes(dao.getCount());//设置分页的总记录数
        pb.setRecordes(dao.findRecordesByPage(pb.getStartIndex(), pb.getPageSize()));//当前页中的记录封装到pageBean
    }

}

JTest.java

package com.itheima.test;

import java.util.List;

import junit.framework.Assert;

import org.junit.Test;

import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;

public class JTest {

    @Test
    public void testCount(){
        AccountDao dao = new AccountDaoImpl();
        int count = dao.getCount();
        //System.out.println(count);
        Assert.assertEquals(7, count);
    }
    @Test
    public void testFindByPage(){
        AccountDao dao = new AccountDaoImpl();
        List list= dao.findRecordesByPage(0, 3);
        //System.out.println(count);
        Assert.assertNotNull(list);
    }
}

C3P0Util.java

package com.itheima.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {

    private static DataSource ds =  new ComboPooledDataSource("mysql");

    /**
     * 获取连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception{
        return ds.getConnection();
    }

    /**
     * 获取数据源
     * @return
     */
    public static DataSource getDataSource(){
        return ds;
    }

    /**
     * 关闭资源
     * 
     * @param rs
     * @param st
     * @param con
     */
    public static void release(ResultSet rs, Statement st, Connection con) {
        // 6.关闭资源
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            st = null;
        }
        if (con != null) {
            try {
                con.close();//不用担心了,肯定还回池中
            } catch (SQLException e) {
                e.printStackTrace();
            }
            con = null;//线程池中也要回收
        }

    }
}

ControllerServlet.java

package com.itheima.web.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.itheima.service.AccountService;
import com.itheima.service.impl.AccountServiceImpl;
import com.itheima.web.form.PageBean;

public class ControllerServlet extends HttpServlet {
    private AccountService as = new AccountServiceImpl();
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.设置编码
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        //2.请求当前的页数
        String pageNo = request.getParameter("pageNo");
        //3.生成分页组件,并设置页数
        PageBean pb = new PageBean();
        if(pageNo!=null){
            pb.setPageNo(Integer.parseInt(pageNo));
        }
        //4.实现分页查询
        as.findRecordesByPage(pb);

        pb.setUrl(request.getContextPath()+"/servlet/ControllerServlet");
        //5.将分页组件保存到request域
        request.setAttribute("pb", pb);


        //6.转发
        request.getRequestDispatcher("/listaccount.jsp").forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);

    }

}

PageBean.java

package com.itheima.web.form;

import java.util.List;

//分页组件用于实现封装分页的相关信息
public class PageBean {
    private int pageNo=1;//当前是第几页
    private int pageSize=3;//每页最多显示几条
    private int prep;//上一页
    private int nextp;//下一页
    private int totalPage;//总页数
    private int totalRecordes;//总记录数
    private int startIndex;//代表分页的起始的索引  (pageNo-1)*pageSize;
    private List recordes;//当前页的所有记录

    private String url;

    //补充添加
    private int startPageNo;//起始页
    private int endPageNo;//结束页


    //每页上面最多有9个数字显示
    public int getStartPageNo() {
        if(getTotalPage()<=9){
            startPageNo=1;
            endPageNo=getTotalPage();
        }else{
            startPageNo=pageNo-4;
            endPageNo=pageNo+4;
            if(startPageNo<=1){
                startPageNo=1;
                endPageNo=startPageNo+8;
            }
            if(endPageNo>=getTotalPage()){
                endPageNo=getTotalPage();
                startPageNo=endPageNo-8;
            }
        }
        return startPageNo;
    }
    public void setStartPageNo(int startPageNo) {
        this.startPageNo = startPageNo;
    }
    public int getEndPageNo() {
        return endPageNo;
    }
    public void setEndPageNo(int endPageNo) {
        this.endPageNo = endPageNo;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public int getPageNo() {
        return pageNo;
    }
    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }
    public int getPageSize() {
        return pageSize;
    }
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public int getPrep() {
        if(pageNo<=1){
            prep=1;
        }else{
            prep=pageNo-1;
        }
        return prep;
    }
    public void setPrep(int prep) {
        this.prep = prep;
    }
    public int getNextp() {
        if(pageNo>=getTotalPage()){
            nextp=getTotalPage();
        }else{
            nextp=pageNo+1;
        }
        return nextp;
    }
    public void setNextp(int nextp) {
        this.nextp = nextp;
    }
    public int getTotalPage() {
        if(totalRecordes%pageSize==0){
            totalPage = totalRecordes/pageSize;
        }else{
            totalPage = totalRecordes/pageSize+1;
        }
        return totalPage;
    }
    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }
    public int getTotalRecordes() {
        return totalRecordes;
    }
    public void setTotalRecordes(int totalRecordes) {
        this.totalRecordes = totalRecordes;
    }
    public int getStartIndex() {
        startIndex = (pageNo-1)*pageSize;
        return startIndex;
    }
    public void setStartIndex(int startIndex) {
        this.startIndex = startIndex;
    }
    public List getRecordes() {
        return recordes;
    }
    public void setRecordes(List recordes) {
        this.recordes = recordes;
    }
}

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day15</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>

    <named-config name="mysql">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day15</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </named-config>


    <named-config name="oracle">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </named-config>
</c3p0-config>

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://blog.163.com/faith_yee/blog/<%=basePath%>">

    <title>My JSP ‘index.jsp‘ starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="http://blog.163.com/faith_yee/blog/styles.css">
    -->
  </head>

  <body>
    <jsp:forward page="/servlet/ControllerServlet"></jsp:forward>
  </body>
</html>

listaccount.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
      </head>
  <body>
        <table border="1" width="600" align="center">
                <tr>
                    <td>ID</td>
                    <td>Name</td>
                    <td>Money</td>
                    <td>操作</td>
                </tr>
                <c:forEach items="${requestScope.pb.recordes }" var="ss">
                    <tr>
                        <td>${ss.id }</td>
                        <td>${ss.name }</td>
                        <td>${ss.money }</td>
                        <td><a href="http://blog.163.com/faith_yee/blog/">删除</a>  <a href="http://blog.163.com/faith_yee/blog/">修改</a></td>
                    </tr>
                </c:forEach>
        </table>

        <!-- 分页 -->
        <%@include file="/commons/page.jsp" %>
  </body>
</html>

当前数据库中的account表

技术分享

首页

技术分享

页2

技术分享

页3

技术分享

在编程时e.printStackTrace()的报错写有好处,提醒我们错误是什么,当项目要发布了删去就好

不会断点调试,活该一辈子做程序员

单元测试的原因:防止扯皮!一个项目在公司里分很多部分,就是三次模型里衍生来的项目中的很多部分,每个部分都可以使用单元测试来检查该部分有没有出现问题!!!!

各个环节不断排查问题,如果一个项目是一个人完成的话,最好在每完成一个部分就使用单元测试来检查环节有没有问题!!

在测试类@Test XXX{}方法里:需要使用断言来测试!Assert.assertEquals(xxx);才专业!!

在@Test类里使用Assert类来测试方法专业

在方法上加@Test就可以测试单元为什么?反射注解

之前老师在业务逻辑层搞的接口和数据处理层的接口没什么区别,其实是老师偷懒,凉拌菜,实际中业务层需要设计更复杂的业务逻辑处理,红烧牛肉面

改造PageBean,加入String URL属性 为了让jsp的路径更简洁,耦合性更低!适用性更强 并在ControllerServlet里给PageBean的Url设置

在WebRoot里新建commons文件夹,里面新建page.jsp:分页组件。(内容和之前的jsp一样,然后在原来的jsp(空白的jsp里使用标签导入))

以后工程使用这种方式导入效率高!

再想在页面中显示(有超链功能)分页码:

需要在PageBean里继续加入属性:

(
    private int startPageNo;//其实页
    private int endPageNo;//结束页
)

在get方法里加入业务():不断挖掘变量之间的关系

getstartPageNo(){
    if(){
        ..
    }else{
            ...
        }
}:先整体思考再把细节补上!

然后在页面组件里加上新增的PageBean属性,显示在页面jsp上

实验思路:

设计好AccountDao-->AccountDaoImpl的功能后,通过AccountServiceImop的功能去控制,从而获取到当前服务器数据库的用来分页的数据,然后该业务逻辑层和数据处理层就搭建成功,接着就是表现层,首先把要表现的页面框架给设计好,在jsp+el表达式把已经封装好了的PageBean里的数据通过待会要设计的servlet传过来。jsp框架设置完后,接下来设计Servlet,servlet在此充当了表现层的控制器(controler),用来控制业务处理层和页面数据并切换,在serlvet里,控制业务处理层的方法去获取数据库中的分页数据,初始化并自定义了自己需要的分页数据封装成PageBean后,就可以用来转发给jsp来表现到页面上了。在jsp还利用了include机制把别的封装后的jsp去调用过来。节省了开发的时间。

总结:数据库数据分页数据---->控制后的数据封装成属性放入PageBean--->页面获取过滤过的PageBean属性表现出来

二、监听器(观察者模式)

1、概述:

现实中:踹宝马车,宝马车响了,主人知道了

事件:踹
事件源:产生该事件的对象(人)
事件监听:车上的报警器
事件处理程序:一女生出来了,另一个男人跑了

实验:

创造java框架

没加监听器的框架--->连关也关不掉

那么我们添加监听
//添加监听:就像宝马车上的报警器
f.addWindowListener(new WindowAdapter(){
    //处理程序:就像宝马报警器响了
    public void windowClosing(WindowEvent e){
        //得到事件源:就像女人跑了,就是找到要关闭的对象
        //WindowEvent是一个事件,可以通过它去获得事件源
        Frame targetSource = (Frame)e.getSource();//事件源!
        //关闭事件源
        targetSource.dispose();//销毁事件源,这样就看到窗口关闭了
    }
});//匿名内部类

实验:day1801listener

项目架构:

技术分享

package com.itheima.test;

import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class FrameTest {

    public static void main(String[] args) {
        Frame f = new Frame();
        f.setSize(200, 150);
        f.setVisible(true);

        //添加监听
        f.addWindowListener( new WindowAdapter() {
            //处理程序
            @Override
            public void windowClosing(WindowEvent e) {
                //1.得到事件源,就是找到要关闭的对象        WindowEvent是一个事件,可能通过它去获得事件源
                Frame targetSource = (Frame)e.getSource();

                //2.关闭事件源
                targetSource.dispose();//销毁事件源,这样就看到窗口关闭了
            }
        });
    }
}

点击关闭按钮关闭

技术分享

2、Servlet规范中的8个监听器

1、监听ServletContext、HttpSession、ServletRequest对象的创建和销毁的监听器

它们分别是ServletContextListener、HttpSessionListener、ServletRequestListener

怎么写?

写一个Listener基本步骤:1、写类、2、配置web.xml

web三大组件:Servlet、监听器、过滤器

项目:day1802weblistener

项目架构:

技术分享

MyHttpSessionAttributeListener.java

package com.itheima.attribute.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class MyHttpSessionAttributeListener implements
        HttpSessionAttributeListener {

    public void attributeAdded(HttpSessionBindingEvent arg0) {
        System.out.println("放了");

    }

    public void attributeRemoved(HttpSessionBindingEvent arg0) {
        System.out.println("删了");

    }

    public void attributeReplaced(HttpSessionBindingEvent arg0) {
        System.out.println("换了");

    }

}

User.java

package com.itheima.domain;

import java.io.Serializable;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;

//感知型监听器HttpSessionBindingListener ,HttpSessionActivationListener
public class User implements Serializable, HttpSessionBindingListener ,HttpSessionActivationListener{

    private String name;
    private String password;

    public User() {
        super();
    }

    public User(String name, String password) {
        super();
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public void valueBound(HttpSessionBindingEvent arg0) {
        System.out.println("User对象被绑架了");

    }

    public void valueUnbound(HttpSessionBindingEvent arg0) {
        System.out.println("User对象被解绑了");

    }

    public void sessionDidActivate(HttpSessionEvent arg0) {
        System.out.println("HttpSessio已激活");

    }

    public void sessionWillPassivate(HttpSessionEvent arg0) {
        System.out.println("HttpSessio钝化");

    }


}

MyServletContextListener.java

package com.itheima.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextListener implements ServletContextListener {

    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("ServletContext已被销毁了");
    }

    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("ServletContext已被创建了");
    }

}

MyServletRequset.java

package com.itheima.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class MyServletRequest implements ServletRequestListener {

    public void requestDestroyed(ServletRequestEvent arg0) {
        System.out.println("ServletRequest被销毁了");

    }

    public void requestInitialized(ServletRequestEvent arg0) {
        System.out.println("ServletRequest被创建了");

    }

}

index.jsp

<%@page import="com.itheima.domain.User"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://blog.163.com/faith_yee/blog/<%=basePath%>">

    <title>My JSP ‘index.jsp‘ starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="http://blog.163.com/faith_yee/blog/styles.css">
    -->
  </head>

  <body>
      <%
      /*    session.setAttribute("p","pp");
        session.setAttribute("pp", "ppp");

        session.removeAttribute("p"); */

        session.setAttribute("p", new User("cgx","123"));
       %>
  </body>
</html>

------------------< ServletContextListener>--------------------

Listener---->MyServletContextListener.java--->继承监听器接口(ServletContextListener)
实现接口带来的两个方法(Context销毁{}\Context初始化)
然后配置web.xml---->

当服务器启动时,servlet也就开始了,也就是servletContext也生成!!
Servlet的生命周期需要课下巩固!

所以开始测试项目:
已启动服务器:在服务器信息里就存在要输出的信息

MyServletContextListenerjava测试结果:

技术分享

------------------< HttpSessionListener>--------------------

listener--->MyHttpSessionListener.java(继承HttpSessioinListener接口)
实现接口带来的两个方法(Context销毁{}\Context初始化)
然后配置web.xml---->把包名/类名复制过去

那么问题来了:session什么被创建呢?当客户端访问servlet时就会产生session,但是如果在servlet声明指令里把session属性改成false时,session就不会产生

tomcat的session周期是30分钟
在tomcat的web.xml配置文件可以查看

MyHttpSessionListenerjava测试结果:

技术分享

------------------< ServletRequestListener>--------------------

Request:当客户端访问时会产生,当客户断开连接时销毁:生命周期短
Listener---->MyServletRequest.java--->继承监听器接口(ServletRequestListener)
实现接口带来的两个方法(Context销毁{}\Context初始化)
然后配置web.xml---->把包名/类名复制过去

所以开始测试项目:
已启动服务器:--->用jsp访问—--发生什么?

MyServletRequestjava测试结果:

技术分享

3、监听域中值的属性变化的监听器

监听ServletContext、HttpSession、ServletRequest域中数据变化的监听器
ServletContextAttributeLister:
HttpSessionAttributeLister:
ServletRequestAttributeLister:
怎么触发以上监听器:调用set、get方法

attribute.lister--->MyHttpSessionAttributLister.java(实现接口:HttpSessionAttributeLister)
实现接口带来的三个方法(added、removed、Replaced)
配置Web.xml
在index.jsp里写jsp代码:<%%>
session.setAttribute("p","pp");
然后访问jsp:然后触发

然后session.removeAttribute("p");
然后访问jsp:然后触发


以上已经介绍了6个监听器(两组)

MyHttpSessionAttributeListenerjava测试结果1:

技术分享

MyHttpSessionAttributeListenerjava测试结果2:

技术分享

MyHttpSessionAttributeListenerjava测试结果3:

技术分享

4、感知型监听器:

这些监听器不需要注册(即不用在xml里配置)。给普通类用

HttpSessionBindingListener:普通类实现了该接口,感知自己何时被HttpSession绑和解绑

HttpSessionActivationListener:普通类实现了该接口,感知自己何时随着HttpSession钝化和激活

技术分享

domin--->User{name、password、有参构造、无参构造,get()、set()}
让以上类实现一个HttpSessionBindingListener
实现方法(valueBound+valueUnbound)

怎么实验?

在index.jsp里
session.setAttribute("p",new User("cgx","123"));

运行!

然后把session.setAttribute("p",new User("cgx","123"));
改成request.setAttribute("p",new User("cgx","123"));
没反应:说明只对session反应

继续拿User实现HttpSessionActivationListener接口
注意:Java可以多实现不可以多继承
然后实现接口方法(sessionDidActivate(激活)+sessionWillPassivate(已钝化))

测试:打开IE访问:主页--->tomcat Manager-->在管理器里的项目名点stop管理器!钝化激活
在work的项目目录下会产生session.ser的文件,就是之前学session时把IE的安全性调到最高时把session保存在客户机的硬盘上!
管理器重启项目后--->激活!
(该程序效果测试失败率高!User 要序列化:当应用(项目)被停的时候,服务器会把这对象写入硬盘保存,以便可以当应用激活时从硬盘调出来,所以User需要加上序列化!!!implements Serializable)

现实中是当内存已满是可以监听到。

要测试每一个监听器的效果建议注销之前的配置

对象序列化-->就是把对象写入文件中

三、显示在线人数,并演示踢人示例

项目:day1803kick

项目架构:

技术分享

User.java

package com.itheima.domain;

import java.io.Serializable;

public class User implements Serializable{

    private String username;
    private String password;

    public User() {
        super();
    }

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }


}

MyHttpSessionAttributeListener.java

package com.itheima.listener;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

import com.itheima.domain.User;

public class MyHttpSessionAttributeListener implements
        HttpSessionAttributeListener {

    public void attributeAdded(HttpSessionBindingEvent se) {
        HttpSession session = se.getSession();
        Object obj =session.getAttribute("user");
        if(obj==null){
            return ;
        }
        if(obj instanceof User){
            User u = (User)obj;

            //2.放入ServletContext中
            ServletContext sc = session.getServletContext();
            //3.因为需要将当前登录的多个用户信息存入ServletContext,所以先产生一个Map集合将登录的所有用户信息
            //存入到Map集合中,最后将Map集合放入ServletContext中

            //Map集合的key:用户名    value:HttpSession
            Map<String,HttpSession> map = (Map<String,HttpSession>)sc.getAttribute("map");
            if(map==null){
                map = Collections.synchronizedMap(new HashMap<String,HttpSession>());//保证线程同步
                sc.setAttribute("map", map);
            }
            map.put(u.getUsername(),session);//这样存值的目的,是在另一台机器上可以得到其它用户的session对象
        }
    }

    public void attributeRemoved(HttpSessionBindingEvent arg0) {
        // TODO Auto-generated method stub

    }

    public void attributeReplaced(HttpSessionBindingEvent arg0) {
        // TODO Auto-generated method stub

    }

}

KickServlet.java

package com.itheima.servlet;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class KickServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        //1.获取参数username
        String username1 = request.getParameter("username");
        //2.对username进行重新编码
        String username = new String(username1.getBytes("iso-8859-1"),"UTF-8");
        //3.找到ServletContext中的Map集合
        ServletContext sc = getServletContext();
        Map<String,HttpSession > map = (Map<String,HttpSession>)sc.getAttribute("map");
        //4.在Map集合中,根据username找到当前的key-value对
        HttpSession session = map.get(username);
        //5.根据value所对应HttpSession,进行销毁操作
        session.invalidate();
        //6.从Map集合中,根据username,删除key-value对
        map.remove(username);

        response.sendRedirect(request.getContextPath());
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);

    }

}

LoginServlet.java

package com.itheima.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.itheima.domain.User;

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //2.接收参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //3.封装成对象
        User user = new User(username,password);

        //4.将user对象保存到session域中
        //当在session域中放入值时,可以让后台的监听器进行监听,
        //并将当前保存的用户信息放入到ServletContext,以实现全局共享
        request.getSession().setAttribute("user", user);

        //5.重定向  
        response.sendRedirect(request.getContextPath()+"/index.jsp");//该页面主要用于显示当前在线的用户,并提供踢人的链接

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);

    }

}

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://blog.163.com/faith_yee/blog/<%=basePath%>">

    <title>My JSP ‘index.jsp‘ starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="http://blog.163.com/faith_yee/blog/styles.css">
    -->
  </head>

  <body>
      <c:if test="${sessionScope.user!=null }">
          <c:forEach items="${applicationScope.map }" var="vv">
                <!-- 为了处理用户名中的中文  c:url会自动针对中文进行编码 -->
                <c:url value="/servlet/KickServlet" var="myurl">
                    <c:param name="username" value="${vv.key }"></c:param>
                </c:url>
                <!-- http://localhost:8080/dsfdsfdsfdsfs?username=%dsfds%dsfs%dfsd -->
                ${vv.key }  <a href="http://blog.163.com/faith_yee/blog/${myurl }">踢人</a>  <br>
          </c:forEach>
      </c:if>

      <c:if test="${sessionScope.user==null }">
            你可能被别人踢了,请重新登录:<a href="http://blog.163.com/faith_yee/blog/${pageContext.request.contextPath }/login.jsp">登录</a>
      </c:if>
  </body>
</html>

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
      </head>
  <body><table width="100%" border="0" cellspacing="0" cellpadding="4">

    <tr> 

        <td bgcolor="#000099"> 

            <table width="100%" border="0" cellspacing="0" cellpadding="4">

                <tr> 

                    <td bgcolor="#FFFFFF">&nbsp;<b>*</b>&nbsp;</td>

                        <td width="100%"><font color="#CCCCCC">&nbsp; <font color="#FFFFFF">Title</font></font></td>

                </tr>

            </table></td>

    </tr>

    <tr> 

        <td width="100%" bgcolor="#EAEAEA" colspan="2"> 

            <form  action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post"><p>

                <label for="textfield">Username</label>

                <br>

                <input type="text" name="username" >

                </p>

                <p>

                <label for="textfield2">Password</label>

                <br>

                <input type="text" name="password" >

                </p>

                <p> 

                <input type="submit"  value="GO">

                </p>

                <p>&nbsp; </p>

                </form>

        </td>

  </tr>

</table>

  </body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.itheima.servlet.LoginServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>KickServlet</servlet-name>
    <servlet-class>com.itheima.servlet.KickServlet</servlet-class>
  </servlet>


  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/servlet/LoginServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>KickServlet</servlet-name>
    <url-pattern>/servlet/KickServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <listener>
        <listener-class>com.itheima.listener.MyHttpSessionAttributeListener</listener-class>
  </listener>
</web-app>

登录login页面

技术分享

进入到index页面

技术分享

总结:

首先设计好javaBean:user,用来把login.jsp传进LoginServlet的数据封装成User对象的。

在Login.jsp里设计的form表单action路径是LoginServlet里,LoginServlet用request.getParament方法去获得Login.jsp传来的信息,封装成对象后就把User对象放入到了Session域对象里了,并把信息利用重定向到index.jsp里了。

然后在MyHttpSessionAttributeListener里实现了session监听器。也就是该servlet本身就是一个监听session对象属性的监听器,因此该监听器会从域对象session里查看session里所存的对象,我们给监听器添加操作,就是当有session存入了对象,监听器就会去判断,但在了解后面的内容之前要明白一个问题:session是域对象,但是只是针对同一个客户端,而servletcontext对象是针对所有客户端。因此在同一个客户端的时候,监听器会把session里的user对象拿出来,为了获得user的具体对象名,并把user的具体对象名和该对象的session存储在servletcontext对象里(注意,存储的方式是把一个Map类型的集合存储进servletcontext对象里,该Map类型集合存储了具体的用户名和对应的session,以供控制踢人的servlet去操作servletcontext对象去删除里面集合的具体用户的session)

然后在先前login.jsp重定向进入到了的index.jsp里,index页面会在当前客户端的session域里检测是否有对象,在有的前提下就利用系统标签去遍历servletcontext域里的所有用户名和session,并把这些信息表现在index页面里,并提供一个连接(连接通向kickservlet),该连接是这个项目的关键部件!通过该连接,kickservlet可以捕获index里的信息,具体用户的用户名,该名可以用来拿出存储在servletcontext对象对应的用户session,在index页面里,如果检查到客户端的session被invalid掉了,所以会强制重定向回login页面

通过超链接《踢出》在kickservlet里获取到了用户名,可以拿出存储在servletcontext对象对应的用户session,并通过从servletcontext对象里,拿到用户的session,把session给invalid掉,并在map里通过用户名取出session,以此来实现把用户踢出的效果。
资料下载

JavaWeb-18 (JDBC之分页与监听器listener)

标签:javaweb

原文地址:http://blog.csdn.net/faith_yee/article/details/44835217

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!