目录
3.创建Statement或者PreparedStatement接口,执行SQL语句
一、Listener介绍
监听器介绍
什么是监听器
Javaweb中的监听器是用于监听web常见对象HttpServletRequest,HttpSession,ServletContext
监听器的作用
1.监听web对象创建与销毁.
2.监听web对象的属性变化
3.监听session绑定javaBean操作.
监听机制相关概念
1.事件----一件事情
2.事件源—产生这件事情的源头
3.注册监听—将监听器与事件绑定,当事件产生时,监听器可以知道,并进行处理。
4.监听器—对某件事情进行处理监听的一个对象
web监听器介绍
1.javaweb监听器介绍
1.监听web对象创建与销毁的监听器
1.ServletContextListener
2.HttpSessionListener
3.ServletRequestListener
2.监听web对象属性变化
1.ServletContextAttributeListener
2.HttpSessionAttributeListener
3.ServletRequestAttributeListener
3.监听session绑定javaBean
1.HttpSessionBindingListener
2.HttpSessionActivationListener
2.javaweb监听器创建步骤
1.创建一个类,实现指定的监听器接口
2.重写接口中的方法.
3.在web.xml文件中配置监听
3.演示监听对象创建与销毁
1.ServletContext对象的创建与销毁监听
ServletContext对象的创建与销毁分析:ServletContext对象是服务器开启时创建。服务器关闭时销毁。
2.HttpSession对象的创建与销毁监听
1.HttpSession对象的创建与销毁分析:
1.session对象创建:取决于请求中是否有jsessinid,如果有,可能会获取一个已经存在的session对象。如果没有,会创建一个新的session对象.
2.销毁session:
1.默认超时 30分钟
2.关闭服务器
3.invalidate()方法
4.setMaxInactiveInterval(int interval) 可以设置超时时间
4.HttpServletRequest对象的创建与销毁监听
1.HttpServletRequest对象的创建与销毁分析:request对象是发送请求时创建,当响应产生时,销毁.
5.监听步骤:
1.创建一个类,实现指定的监听器接口
2.重写接口中的方法
3.在web.xml文件中对监听器进行注册。
二、监听域对象的生命周期
要想对Servlet域对象的生命周期进行监听,需要实现域对应的3.ServletContextListener,HttpSessionLister和ServletRequestListener接口
实现步骤
1.创建监听器,实现监听器接口
package cn.itcast.chapter08.listener;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyListener implements
ServletContextListener, HttpSessionListener,ServletRequestListener {
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContext对象被创建了");
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContext对象被销毁了");
}
public void requestInitialized(ServletRequestEvent arg0) {
System.out.println("ServletRequest对象被创建了");
}
public void requestDestroyed(ServletRequestEvent arg0) {
System.out.println("ServletRequest对象被销毁了");
}
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("HttpSession对象被创建了");
}
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("HttpSession对象被销毁了");
}
}
2.添加监听器类信息
一个完整的Servlet事件监听器包括Listener类和<listener>配置信息,而一个web.xml中可以配置多个监听器。同一种类型的监听器也可以配置多个,触发的时候服务器会顺序执行各个监听器的相应方法。
3.启动项目,查看servletContext对象创建信息
4.关闭项目,查看ServletContext对象销毁信息
5.创建测试页面
查看HttpSessionListener和ServletRequestListener监听器的运行效果,创建myjsp.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<title>this is MyJsp.jsp page</title>
</head>
<body>
这是一个测试监听器的页面
</body>
</html>
6.设置监听超时信息
<session-timeout>标签指定的超时必须为一个整数。如果这个整数为0或负整数,则session永远不会超时;如果这个数是正整数,则项目中的session将在指定分钟后超时。
7.重启项目,查看结果
zai
再次刷新
再次访问myjsp.jsp页面,在控制台窗口中会再次输出ServletRequest对象被创建与被销毁的信息,但不会创建新的用了HttpSession对象。这是因为Web容器会为每次访问请求都创建一个新的ServletRequest对象,而对于同一个浏览器在会话期间的后续访问是不会再创建新的HttpSession对象的。
HttpSession对象被销毁了,Web服务器调用了监听器对象的sessionDestroyed()方法。
三、 监听域对象的属性变更
实现步骤
1.创建测试页面
观察各个对象域对象属性性监听器的作用
2.创建监听器
实现接口所有方法
package cn.itcast.chapter08.listener;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyAttributeListener implements ServletContextAttributeListener,
HttpSessionAttributeListener, ServletRequestAttributeListener {
public void attributeAdded(ServletContextAttributeEvent sae) {
String name = sae.getName();
System.out.println("ServletContext添加属性:" + name + "="
+ sae.getServletContext().getAttribute(name));
}
public void attributeRemoved(ServletContextAttributeEvent sae) {
String name = sae.getName();
System.out.println("ServletContext移除属性: " + name);
}
public void attributeReplaced(ServletContextAttributeEvent sae) {
String name = sae.getName();
System.out.println("ServletContext替换属性:" + name + "="
+ sae.getServletContext().getAttribute(name));
}
public void attributeAdded(HttpSessionBindingEvent hbe) {
String name = hbe.getName();
System.out.println("HttpSession添加属性:" + name + "="
+ hbe.getSession().getAttribute(name));
}
public void attributeRemoved(HttpSessionBindingEvent hbe) {
String name = hbe.getName();
System.out.println("HttpSession移除属性: " + name);
}
public void attributeReplaced(HttpSessionBindingEvent hbe) {
String name = hbe.getName();
System.out.println("HttpSession替换属性:" + name + "="
+ hbe.getSession().getAttribute(name));
}
public void attributeAdded(ServletRequestAttributeEvent sra) {
String name = sra.getName();
System.out.println("ServletRequest添加属性:" + name + "="
+ sra.getServletRequest().getAttribute(name));
}
public void attributeRemoved(ServletRequestAttributeEvent sra) {
String name = sra.getName();
System.out.println("ServletRequest移除属性: " + name);
}
public void attributeReplaced(ServletRequestAttributeEvent sra) {
String name = sra.getName();
System.out.println("ServletRequest替换属性:" + name + "="
+ sra.getServletRequest().getAttribute(name));
}
}
3.添加监听信息
4.启动项目,查看结果
可以看出,在ServletContext、HttpSession和ServletRequest 3个域对象中.
分别完成了增加、替换和删除username属性值的操作。
四、JDBC
1.什么是JDBC
JDBC的全称是Java数据库连接(Java Database Connectivity),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、更新、新增和删除的操作。
2.JDBC编程步骤
1.装载相应数据库的JDBC驱动并进行初始化
- 导入专用的jar包(不同的数据库需要的jar包不同)
访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个.Jar的文件里。mysql-connector-java-5.0.8-bin.jar包可以在网上下载,或者在MySQL的安装目录下找到。通常下载到该jar包之后将其放到在项目的lib目录下
导包步骤: 右键project->property->java build path->libaries->add external jars
如果没有完成上述步骤的导包操作,后面会抛出ClassNotFoundException
- 初始化驱动
通过初始化驱动类com.mysql.jdbc.Driver,该类就在 mysql-connector-java-5.0.8-bin.jar中。如果你使用的是oracle数据库那么该驱动类将不同。
注意:Class.forName需要捕获ClassNotFoundException.
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class.forName是把这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作。
2.建立JDBC和数据库之间的Connection连接
这里需要提供:数据库服务端的IP地址:127.0.0.1 (这是本机,如果连接其他电脑上的数据库,需填写相应的IP地址)
数据库的端口号: 3306 (mysql专用端口号)
数据库名称 test(根据你自己数据库中的名称填写)
编码方式 UTF-8
账号 root
密码 root(如果你在创建数据库的时候没有使用默认的账号和密码,请填写自己设置的账号和密码)
Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8", "root", "root");
//(string url,string user,string pwd)
//jdbc:mysql://hostname:port/databasename
//(hostname可以为localhost或127.0.0.1)
Connection是与特定数据库连接回话的接口,使用的时候需要导包,而且必须在程序结束的时候将其关闭。getConnection方法也需要捕获SQLException异常。
public static void main(String[] args) throws SQLException {
Connection conn = null;
PreparedStatement preStmt = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jdbc";
String username = "root";
String password = "root";
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
3.创建Statement或者PreparedStatement接口,执行SQL语句
- 使用Statement接口
通过Connection对象获取Statement对象Connection创建Statement的方式有如下3种。
- createStatement():创建基本的Statement对象。
- prepareStatement(): 创建PreparedStatement对象。
- prepareCall():创建CallableStatement对象。
基本的Statement
statement stmt=conn.createStatement();
Statement接口创建之后,可以执行SQL语句,完成对数据库的增删改查。其中 ,增删改只需要改变SQL语句的内容就能完成,然而查询略显复杂。在Statement中使用字符串拼接的方式,该方式存在句法复杂,容易犯错等缺点,具体在下文中的对比中介绍。所以Statement在实际过程中使用的非常的少,所以具体的放到PreparedStatement那里给出详细代码。
字符串拼接方式的SQL语句是非常繁琐的,中间有很多的单引号和双引号的混用,极易出错。
Statement s = conn.createStatement();
// 准备sql语句
// 注意: 字符串要用单引号'
String sql = "insert into t_courses values(null,"+"'数学')";
//在statement中使用字符串拼接的方式,这种方式存在诸多问题
s.execute(sql);
System.out.println("执行插入语句成功");
- 使用PreparedStatement接口
与 Statement一样,PreparedStatement也是用来执行sql语句的与创建Statement不同的是,需要根据sql语句创建PreparedStatement。除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接。
注意:
使用PreparedStatement时,他的SQL语句不再采用字符串拼接的方式,而是采用占位符的方式。“?”在这里就起到占位符的作用。这种方式除了避免了statement拼接字符串的繁琐之外,还能够提高性能。每次SQL语句都是一样的,java类就不会再次编译,这样能够显著提高性能。
String sql = "update t_course set course_name =? where course_id=?";
Statement s = conn.createStatement();
// 准备sql语句
// 注意: 字符串要用单引号'
String sql = "INSERT INTO users(name,password,email,birthday)"
+ "VALUES(?,?,?,?)";
//在statement中使用字符串拼接的方式,这种方式存在诸多问题
s.execute(sql);
System.out.println("执行插入语句成功");
后面需要用到PreparedStatement接口创建的pstmt的set方法给占位符进行赋值。注意一点,这里的参数索引是从1开始的。
preStmt = conn.prepareStatement(sql);
preStmt.setString(1, "zl");
preStmt.setString(2, "123456");
preStmt.setString(3, "zl@sina.com");
preStmt.setString(4, "1789-12-23");
preStmt.executeUpdate();
增删改都使用pstmt.executeUpdate();语句进行SQL语句的提交
4.使用Statement 执行SQL语句
所有的Statement 都有如下3种执行SQL语句的方法。
- execute():可以执行任何SQL语句。
- executeQuery():通常执行查询语句,执行后返回代表结果集的ResultSet对象。
- executeUpdate():主要用于执行DML和DDL语句。执行DML语句,如 INSERT、UPDATE或DELETE时,返回受SQL语句影响的行数,执行DDL语句返回0。
以 executeQuery()方法为例,其使用方式如下。
//执行SQL语句,获取结果集
ResultSetResultSet rs = stmt.executeQuery (sql);
5.操作ResultSet结果集
如果执行的SQL语句是查询语句,执行结果将返回一个ResultSet对象,该对象里保存了
SQL语句查询的结果。程序可以通过操作该ResultSet对象来取出查询结果。
6.关闭连接,释放资源
每次操作数据库结束后都要关闭数据库连接,释放资源,包括关闭ResultSet、Statement
和Connection等资源。
至此,JDBC程序的大致实现步骤已经讲解完成。接下来,依照上面所讲解的步骤来演示
JDBC的使用。该程序从users表中读取数据,并将结果打印在控制台,
具体步骤
1.搭建数据库环境
在MySQL中创建一个名称为jdbc的数据库,然后在该数据库中创建一个users表
数据库和表的SQL语句如下所示。
CREATE DATABASE jdbc;
USE jdbc;
CREATE TABLE users (
id INT PRIMARY KEY AUTO INCREMENT,name VARCHAR(40),
password VARCHAR(40),
email VARCHAR(60),
birthday DATE
)CHARACTER SET utf8 COLLATE utf8_general_ci;
数据库和表创建成功后,再向users表中插入3条数据,插入的SQL语句如下所示。
INSERT INTO users (NAME,PASSWORD, email,birthday)VALUES('zs','123456', 'zs0sina.com', '1980-12-04');
INSERT INTO users(NAME,PASSWORD,email,birthday)
VALUES('lisi', '123456', 'lisi0sina.com','1981-12-04');INSERT INTO users (NAME,PASSWORD,email,birthday)
VALUES('wangwu','123456', 'wangwu@sina.com','1979-12-04');
2.创建项目环境,导入数据库驱动
导入下载好的MySQL数据库驱动文件
3.编写JDBC程序
创建Example01,用于读取数据库中的users表,并将结果输出控制台
package cn.itcast.jdbc.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Date;
public class Example01 {
public static void main(String[] args) throws SQLException {
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
// 1. 注册数据库的驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.通过DriverManager获取数据库连接
String url = "jdbc:mysql://localhost:3306/jdbc";
String username = "root";
String password = "root";
conn = DriverManager.getConnection (url, username,
password);
// 3.通过Connection对象获取Statement对象
stmt = conn.createStatement();
// 4.使用Statement执行SQL语句。
String sql = "select * from users";
rs = stmt.executeQuery(sql);
// 5. 操作ResultSet结果集
System.out.println("id | name | password | email | birthday");
while (rs.next()) {
int id = rs.getInt("id"); // 通过列名获取指定字段的值
String name = rs.getString("name");
String psw = rs.getString("password");
String email = rs.getString("email");
Date birthday = rs.getDate("birthday");
System.out.println(id + " | " + name + " | " + psw + " | " + email
+ " | " + birthday);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally{
// 6.回收数据库资源
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
}
首先注册了MySQL数据库驱动,通过DriverManager获取一个Connection对象,然后使用Connection对象创建一个Statement对象,Statement对象通过executeQuery()方法执行SQL语句,并返回结果集ResultSet。接下来,通过遍历ResultSet得到最终的查询结果,最后关闭连接,回收了数据库资源。
程序执行成功后,控制台的打印结果如图所示
注意:
- 注册驱动
虽然使用 DriverManager.registerDriver(new com.mysql.jdbc.Driver())方法也可以完成注
册,但此方式会使数据库驱动被注册两次。这是因为Driver类的源码已经在静态代码块中完成了
数据库驱动的注册。所以,为了避免数据库驱动被重复注册,只需在程序中使用Class.forName()
方法加载驱动类即可。
由于数据库资源非常宝贵,数据库允许的并发访问连接数量有限,因此,当数据库资源使用
- 释放资源
完毕后,一定要记得释放资源。为了保证资源的释放,在Java程序中,应该将最终必须要执行的操作放在 finally 代码块中。
创建Example02的类,在类中使用PreparedStatement对象对数据库进行插入数据的操作,预编译信息储存在PreparedStatement对象,提高数据访问效率
package cn.itcast.jdbc.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement ;
import java.sql.SQLException;
public class Example02 {
public static void main(String[] args) throws SQLException {
Connection conn = null;
PreparedStatement preStmt = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jdbc";
String username = "root";
String password = "root";
// 创建应用程序与数据库连接的Connection对象
conn = DriverManager.getConnection(url, username, password);
// 执行的SQL语句
String sql = "INSERT INTO users(name,password,email,birthday)"
+ "VALUES(?,?,?,?)";
// 创建执行SQL语句的PreparedStatement 对象
preStmt = conn.prepareStatement(sql);
preStmt.setString(1, "zl");
preStmt.setString(2, "123456");
preStmt.setString(3, "zl@sina.com");
preStmt.setString(4, "1789-12-23");
preStmt.executeUpdate();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally { // 释放资源
if (preStmt != null) {
try {
preStmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
preStmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
}
首先通过Connection对象的prepareStatement()方法生成PreparedStatement对象,然后调用PreparedStatement对象的setXxx()方法,给SQL语句中的参数赋值,最后通讨调executeUpdate()方法执行SQL语句。
文件运行成功后,会在users表中插入一条数据。进入MySQL数据库,使用SELECT句查看users表,查询结果如9-5所示。