标签:javaweb
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属性表现出来
现实中:踹宝马车,宝马车响了,主人知道了
事件:踹
事件源:产生该事件的对象(人)
事件监听:车上的报警器
事件处理程序:一女生出来了,另一个男人跑了
实验:
创造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();//销毁事件源,这样就看到窗口关闭了
}
});
}
}
点击关闭按钮关闭
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"> <b>*</b> </td>
<td width="100%"><font color="#CCCCCC"> <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> </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