JDBC、XML、SERVLET、COOKIE&SESSION、JSP、EL$JSTL阶段总结
JDBC
JDBC(Java Date Base Connectivity.java数据库连接)是一种用于执行SQL语句的javaAPI.可以为多种数据库提供统一的访问,它由一种用Java语言编写的类和接口的组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用的程序,同时,JDBC也是个商标名。
什么是数据库驱动
驱动:两个设备(应用)之间通信的桥梁。
JDBC的环境准备
1、创建数据库和表
2、创建项目,引入jar包
建一个lib文件将mysql-connector-java-5.0.8-bin.jar粘贴如此
JDBC的代码实现
JDBC的开发步骤
第一步:加载驱动
第二步:获得连接
第三步:基本操作
第四步:释放资源
bli
JDBC的代码实现
import org.junit.Test;
/**
* JDBC的入门程序
* @author jt
*
*/
public class JDBCDemo1 {
@Test
/**
* JDBC的入门
*/
public void demo1() throws Exception{
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获得连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web_test3", "root", "abc");
// 3.基本操作:执行SQL
// 3.1获得执行SQL语句的对象
Statement statement = conn.createStatement();
// 3.2编写SQL语句:
String sql = "select * from user";
// 3.3执行SQL:
ResultSet rs = statement.executeQuery(sql);
// 3.4遍历结果集:
while(rs.next()){
System.out.print(rs.getInt("id")+" ");
System.out.print(rs.getString("username")+" ");
System.out.print(rs.getString("password")+" ");
System.out.print(rs.getString("nickname")+" ");
System.out.print(rs.getInt("age"));
System.out.println();
}
// 4.释放资源
rs.close();
statement.close();
conn.close();
}
}
********************************************************************
JDBC的API详解之DriverManager
DriverManager:驱动管理类
管理一组 JDBC 驱动程序的基本服务
作用一:注册驱动
static void registerDriver(Driver driver)
向 DriverManager 注册给定驱动程序
这个方法可以完成驱动的注册,但是实际开发中一般不会使用这个方法完成驱动的注册!!!
原因:
如果需要注册驱动,就会使用DriverManager.registerDriver(new Driver());,但是查看源代码发现,在代码中有一段静态代码块,静态代码块已经调用了注册驱动的方法。
如果再手动调用该方法注册驱动,就会导致驱动被注册两次。实际开发中一般会采用:
class.forName("com.mysql.jabc.Driver");
作用二:获得连接
static Connection getConnection(String url, String user,String password)
试图建立到给定数据库 URL 的连接。
这个方法就是用来获得与数据库连接的方法:这个方法中有三个参数:
url:与数据库连接的路径
user:与数据库连接的用户名
password:与数据库连接的密码
主要关注的是url的写法:
jdbc:mysql://localhost:3306/web_test3
jdbc:连接数据库的协议
mysql:是jdbc的子协议
localhost:连接的MySQL数据库服务器的主机地址。(连接是本机就可以写成localhost),如果连接不是本机的,就需要写上连接主机的IP地址。
3306:MySQL数据库服务器的端口号
web_test3:数据库名称
jdbc:mysql:///web_test3
JDBC的API详解之Connection
Connection:与数据库连接对象
作用一:创建执行SQL语句的对象
执行SQL语句对象:
Statement :执行SQL
CallableStatement :执行数据库中存储过程
PreparedStatement :执行SQL.对SQL进行预处理。解决SQL注入漏洞
作用二:管理事务
void setAutoCommit(boolean autoCommit)
将此连接的自动提交模式设置为给定状态。
void commit()
使所有上一次提交/回滚后进行的更改成为持久更改,并释放此Connection 对象当前持有的所有数据库锁。
void rollback()
取消在当前事务中进行的所有更改,并释放此 Connection 对象当前持有的所有数据库锁。
JDBC的API详解之Statement
Statement:执行SQL
作用一:执行SQL
执行SQL的方法
boolean execute(String sql);
执行查询,修改,添加,删除的SQL语句。
ResultSet executeQuery(String sql);
执行查询(执行select语句)。
int executeUpate(String sql);
执行修改,添加,删除的SQL语句。
作用二:执行批处理
void addBatch(String sql)
将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。
void clearBatch()
清空此 Statement 对象的当前 SQL 命令列表。
int[] executeBatch()
将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。
JDBC的API详解之ResultSet
ResultSet:结果集---通过select语句的查询结果。
结果集的遍历 利用next的方法
boolean next()
将光标从当前位置向前移一行
结果集的获取
int getInt(int columnIndex)
以 Java 编程语言中 int 的形式获取此 ResultSet 对象的当前行中指定列的值。
int getInt(String columnLabel)
以 Java 编程语言中 int 的形式获取此 ResultSet 对象的当前行中指定列的值。
long getLong(int columnIndex)
以 Java 编程语言中 long 的形式获取此 ResultSet 对象的当前行中指定列的值。
long getLong(String columnLabel)
以 Java 编程语言中 long 的形式获取此 ResultSet 对象的当前行中指定列的值。
String getString(int columnIndex)
以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值。
String getString(String columnLabel)
以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值。
结果集获取可以使用结果集中的:
getXXX();方法通常都会有一个重载的方法。
getXXX(int columnIndex);
getXXX(String columnName);
**********************************************************************
JDBC的资源释放
JDBC程序执行结束后,将与数据库进行交互的对象释放掉,
通常是ResultSet,Statement,Connection。
注意Connection对象的释放
这几个对象中尤其是Connection对象是非常稀有的。
这个对象一定要做到尽量晚创建,尽早释放掉。
将资源释放的代码写入到finally的代码块中。
资源释放的代码应该写的标准:
if(rs !=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(statement !=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if(conn !=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
**********************************************************************JDBC的CRUD操作之保存操作
@Test
/**
* 保存操作的代码实现
*/
public void demo1(){
Connection conn = null;
Statement stmt = null;
try{
// 注册驱动:
Class.forName("com.mysql.jdbc.Driver");
// 获得连接:
conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
// 执行操作:
// 创建执行SQL语句对象:
stmt = conn.createStatement();
// 编写SQL语句:
String sql = "insert into user values (null,'eee','123','阿黄',21)";
// 执行SQL语句:
int num = stmt.executeUpdate(sql);
if(num > 0){
System.out.println("保存用户成功!!!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 资源释放:
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;
}
}
}
**********************************************************************
JDBC的CURD操作之修改操作
@Test
/**
* 修改操作的代码实现
*/
public void demo2(){
Connection conn = null;
Statement stmt = null;
try{
// 注册驱动:
Class.forName("com.mysql.jdbc.Driver");
// 获得连接
conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
// 执行操作:
// 创建执行SQL语句的对象:
stmt = conn.createStatement();
// 编写SQL语句:
String sql = "update user set password='abc',nickname='旺财' where id = 5";
// 执行SQL语句:
int num = stmt.executeUpdate(sql);
if(num > 0){
System.out.println("修改用户成功!!!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 资源释放:
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;
}
}
}
**********************************************************************
JDBC的工具类的抽取
因为传统JDBC的开发,注册驱动,获得连接,释放资源这些代码都是重复编写
的。所以可以将重复的代码提取到一个类中来完成。
/**
* JDBC的工具类
* @author jt
*
*/
public class JDBCUtils {
private static final String driverClassName;
private static final String url;
private static final String username;
private static final String password;
static{
driverClassName="com.mysql.jdbc.Driver";
url="jdbc:mysql:///web_test3";
username="root";
password="abc";
}
/**
* 注册驱动的方法
*/
public static void loadDriver(){
try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获得连接的方法
*/
public static Connection getConnection(){
Connection conn = null;
try{
// 将驱动一并注册:
loadDriver();
// 获得连接
conn = DriverManager.getConnection(url,username, password);
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
/**
* 释放资源的方法
*/
public static void release(Statement stmt,Connection conn){
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;
}
}
public static void release(ResultSet rs,Statement stmt,Connection conn){
// 资源释放:
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;
}
}
}
1.1.2 测试工具类
@Test
/**
* 查询操作:使用工具类
*/
public void demo1(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 创建执行SQL语句的对象:
stmt = conn.createStatement();
// 编写SQL:
String sql = "select * from user";
// 执行查询:
rs = stmt.executeQuery(sql);
// 遍历结果集:
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 释放资源:
JDBCUtils.release(rs, stmt, conn);
}
}
*********************************************************************
JDBC的配置信息提取到配置文件
配置文件
属性文件
格式:扩展名是.properties
内容:key=value
XML文件
提取信息到配置文件
定义一个配置文件
在工具类中解析属性文件
获取到具体内容为常量赋值
static{
//获取属性文件中的内容
Properties properties=new Properties();
try {
properties.load(new FileInputStream("src/db.properties"));
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
diverClassName=Properties.getProperty("driverClassName");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
}
*********************************************************************
JDBC的CRUD操作之PreparedStatement的保存操作
@Test
/**
* 保存操作
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 编写SQL语句:
String sql = "insert into user values (null,?,?,?,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "eee");
pstmt.setString(2, "abc");
pstmt.setString(3, "旺财");
pstmt.setInt(4, 32);
// 执行SQL
int num = pstmt.executeUpdate();
if(num > 0){
System.out.println("保存成功!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
*********************************************************************
JDBC的CRUD操作之PreparedStatement的修改操作
@Test
/**
* 修改操作
*/
public void demo2(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 编写SQL语句:
String sql = "update user set username = ?,password =?,nickname=?,age = ? where id = ?";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "abc");
pstmt.setString(2, "1234");
pstmt.setString(3, "旺旺");
pstmt.setInt(4, 23);
pstmt.setInt(5, 6);
// 执行SQL:
int num = pstmt.executeUpdate();
if(num > 0){
System.out.println("修改成功!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
*********************************************************************
JDBC的CRUD操作之PreparedStatement的查询操作
@Test
/**
* 查询操作
*/
public void demo4(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 编写SQL:
String sql = "select * from user";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 执行SQL:
rs = pstmt.executeQuery();
// 遍历结果集:
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
}
********************************************************************
JDBC的批处理操作
什么是批处理
之前进行JDBC的操作的时候,都是一条SQL语句执行。现在如果使用批处理,
可以将一批SQL一起执行。
批处理基本使用
@Test
/**
* 批处理基本操作
*/
public void demo1(){
Connection conn = null;
Statement stmt = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 创建执行批处理对象:
stmt = conn.createStatement();
// 编写一批SQL语句:
String sql1 = "create database test1";
String sql2 = "use test1";
String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
String sql4 = "insert into user values (null,'aaa')";
String sql5 = "insert into user values (null,'bbb')";
String sql6 = "insert into user values (null,'ccc')";
String sql7 = "update user set name = 'mmm' where id = 2";
String sql8 = "delete from user where id = 1";
// 添加到批处理
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
stmt.addBatch(sql4);
stmt.addBatch(sql5);
stmt.addBatch(sql6);
stmt.addBatch(sql7);
stmt.addBatch(sql8);
// 执行批处理:
stmt.executeBatch();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(stmt, conn);
}
}
批量插入(使用PreparedStatement)
@Test
/**
* 批量插入记录:
* * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。
*/
public void demo2(){
// 记录开始时间:
long begin = System.currentTimeMillis();
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtils.getConnection();
// 编写SQL语句:
String sql = "insert into user values (null,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
for(int i=1;i<=10000;i++){
pstmt.setString(1, "name"+i);
// 添加到批处理
pstmt.addBatch();
// 注意问题:
// 执行批处理
if(i % 1000 == 0){
// 执行批处理:
pstmt.executeBatch();
// 清空批处理:
pstmt.clearBatch();
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
long end = System.currentTimeMillis();
System.out.println((end-begin));
}
事物管理的核心思想
业务逻辑的操作要使用同一个Connection对象
高可用
代码层面
代码的复用性:把一些相同的或者相似的操作抽取出来
面向接口的编程
public voic adb(List list)利用到了多肽
设计模式:装饰者模式
务的概念:
事务指的是逻辑上的一组操作,组成这组操作各个逻辑单元要么全都成功,要么全都失败。
转账案例代码实现;
@Test
/**
* 完成转账的案例
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
/**
* 完成转账代码:
* * 扣除某个账号的钱
* * 给另外一个账号加钱
*/
// 获得连接:
conn = JDBCUtils.getConnection();
// 编写SQL语句:
String sql = "update account set money = money + ? where name = ?";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 用aaa账号给bbb账号转1000元
pstmt.setDouble(1, -1000);
pstmt.setString(2, "aaa");
// 执行SQL:扣除aaa账号1000元
pstmt.executeUpdate();
// int i = 1 / 0;
// 给bbb账号加1000
pstmt.setDouble(1, 1000);
pstmt.setString(2, "bbb");
pstmt.executeUpdate();
}catch(Exception e){ e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
在转账中没有添加事务的管理,出现aaa账号的钱被转丢了,但是bbb账号的钱没有任何变化。需要给转账的功能添加事务的管理。
在转账中添加事务管理:
void setAutoCommit(boolean autoCommit)
将此连接的自动提交模式设置为给定状态。
void commit()
使所有上一次提交/回滚后进行的更改成为持久更改,并释放此 Connection 对象当前持有的所有数据库锁。
void rollback()
取消在当前事务中进行的所有更改,并释放此 Connection 对象当前持有的所有数据库锁。
@Test
/**
* 完成转账的案例
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
/**
* 完成转账代码:
* * 扣除某个账号的钱
* * 给另外一个账号加钱
*/
// 获得连接:
conn = JDBCUtils.getConnection();
// 开启事务
conn.setAutoCommit(false);
// 编写SQL语句:
String sql = "update account set money = money + ? where name = ?";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 用aaa账号给bbb账号转1000元
pstmt.setDouble(1, -1000);
pstmt.setString(2, "aaa");
// 执行SQL:扣除aaa账号1000元
pstmt.executeUpdate();
int i = 1 / 0;
// 给bbb账号加1000
pstmt.setDouble(1, 1000);
pstmt.setString(2, "bbb");
pstmt.executeUpdate();
// 提交事务:
conn.commit();
}catch(Exception e){
// 回滚事务:
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
什么是连接池
连接池是装有连接的容器,使用连接的话,可以从连接池中进行获取,使用完成之后将连接归还给连接池。
为什么要学习连接池
连接对象创建和销毁是需要耗费时间的,在服务器初始化的时候就初始化一些连接。把这些连接放入到内存中,使用的时候可以从内存中获取,使用完成之后将连接放入连接池中。从内存中获取和归还的效率要远远高于创建和销毁的效率。(提升性能)。
自定义连接池
代码实现
public calss MyDaSource implements DataSource{
//将一些连接存入内存中,可以定义一个集合,用于存储连接对象
private List<Connection> connList=new ArrayList<Connection>();
//在初始化的时候提供一些连接
public MyDataSource(){
//初始化连接
for(int i=1;i<=3;i++){
//向集合中存入连接
connList.add(JDBCUtills.getConnection());
}
}
//从连接池中获取连接的方法
@Override
public Connection getConnection() throws SQLException{
Connection conn=connList.remove(0);
return conn;
}
//编写一个归还连接的方法;
public void addBack(Connection conn){
connList.add(conn);
}
}
自定义连接池的问题及解决分析
使用接口的实现类完成的构造
MyDataSource dataSource = new MyDataSource();
这种写法不方便程序的扩展。
额外提供了方法归还连接
// 归还连接:
dataSource.addBack(conn);
这种方式增加使用连接池的用户的难度。
自定义连接池的问题解决
如果不提供自定义的方法就可以解决这个问题,但是连接要如何归还到连接池呢?
解决分析的思路
原来在Connection中是有一个close方法的,colse方法完成了连接的销毁。能不能做一个事情,将原有的连接的close方法改为归还。
现在要做的事情就是将原有的close方法的逻辑改为归还。(增强一个类中的方法)。
如何增强一个类中的方法
一种:采用继承的方式:
***** 继承这种增强是最简单,但是是有使用条件的:必须能够控制这个类的构造!!!
class Man{
public void run(){
System.out.println(“跑…”);
}
}
class SuperMan extends Man{
public void run(){
System.out.println(“飞…”);
}
}
二种:采用装饰者模式:
***** 装饰者模式使用条件:
* 一、增强的类和被增强的类实现相同的接口
* 二、在增强的类中获得被增强的类的引用
装饰者模式
interface Waiter{
public void server();
}
public class Waitress implements Waiter{
public void server(){
System.out.println(“服务中…”);
}
}
public class WaitressWrapper implements Waiter{
private Waiter waiter;
public WaitressWrapper(Waiter waiter){
this.waiter = waiter;
}
public void server(){
System.out.println(“微笑…”)
waiter.server();
}
}
使用装饰者模式增强Connection中的close方法
为了简化编程,提供一个模板类(模板类原封不动的将接口中的所有方法都实现,但是都没有增强)。编写一个装饰类继承模板类。在装饰类中只需要增强某一个方法即可。
改写连接池
public class MyDataSource implements DataSource {
// 将一些连接存入到内存中,可以定义一个集合,用于存储连接对象。
private List<Connection> connList = new ArrayList<Connection>();
// 在初始化的时候提供一些连接
public MyDataSource() {
// 初始化连接:
for(int i = 1;i<=3;i++){
// 向集合中存入连接:
connList.add(JDBCUtils.getConnection());
}
}
// 从连接池中获得连接的方法
@Override
public Connection getConnection() throws SQLException {
Connection conn = connList.remove(0);
// 增强连接:
MyConnectionWrapper connWrapper = new MyConnectionWrapper(conn, connList);
return connWrapper;
}
// 编写一个归还连接的方法:
/*public void addBack(Connection conn){
connList.add(conn);
}*/
}
Druid的概述
Druid阿里旗下开源连接池产品,使用非常简单,可以与Spring框架进行快速整合。
Druid的使用
@Test
/**
* Druid的使用:
* * 手动设置参数的方式
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 使用连接池:
DruidDataSource dataSource = new DruidDataSource();
// 手动设置数据库连接的参数:
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///web_test4");
dataSource.setUsername("root");
dataSource.setPassword("abc");
// 获得连接:
// conn = JDBCUtils.getConnection();
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from account";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 执行SQL:
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
}
使用配置方式完成连接池的使用
@Test
/**
* Druid的使用:
* * 配置方式设置参数
* Druid配置方式可以使用属性文件配置的。
* * 文件名称没有规定但是属性文件中的key要一定的。
*/
public void demo2(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 使用连接池:
// 从属性文件中获取:
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 获得连接:
// conn = JDBCUtils.getConnection();
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from account";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 执行SQL:
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
}
C3P0的连接池的概述
C3P0的连接池的使用
@Test
/**
* 手动设置参数的方式:
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 获得连接:从连接池中获取:
// 创建连接池:
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 设置连接参数:
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///web_test4");
dataSource.setUser("root");
dataSource.setPassword("abc");
// 从连接池中获得连接:
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from account";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 执行SQL:
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
}
采用配置文件的方式:
使用连接池
@Test
/**
* 采用配置文件的方式:
*/
public void demo2(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 获得连接:从连接池中获取:
// 创建连接池://创建连接池默认去类路径下查找c3p0-config.xml
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 从连接池中获得连接:
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from account";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 执行SQL:
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs, pstmt, conn);
}
}
什么是DBUtils
Commons DbUtils是Apache组织提供的一个队JDBC进行简单封装的开元工具类
使用它能简化JDBC程序的开发,同时也不会影响程序的性能。
为什么要学习DBUtils
因为JDBC手写比较麻烦,而且有非常多的代码是类似的。比如获得连接,预编译SQL,释放资源等..那么可以将这些代码抽取出来放到工具类中。将类似的代码进行抽取。大大简化JDBC的编程
DBUtils的API的概述
QueryRunner对象:核心运行类
构造方法
在一般情况下如果执行CRUD的操作
构造:
QueryRunner(DataSource ds);
方法:
int update(String sql,Object… args);
T query(String sql,ResultSetHandler rsh,Object… args);
如果有事务管理的话使用另一套完成CRUD的操作
构造:
QueryRunner();
方法:
int update(Connection conn,String sql,Object… args);
T query(Connection conn,String sql,ResultSetHandler rsh,Object… args);
D
BUtils的添加操作
@Test
/**
* 添加操作
*/
public void demo1() throws SQLException{
// 创建核心类:QueryRunner:
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
queryRunner.update("insert into account values (null,?,?)", "ddd",10000);
}
DBUtils的修改操作
@Test
/**
* 修改操作
*/
public void demo2() throws SQLException{
// 创建核心类:
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
queryRunner.update("update account set name=?,money=? where id =?", "eee",20000,4);
}
DBUtils的删除操作
@Test
/**
* 删除操作
*/
public void demo3() throws SQLException{
// 创建核心类:
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
queryRunner.update("delete from account where id = ?", 3);
}
***************************************************************************************************
WEB08-XML&Tomcat
学目标:了解XML的基本语法,并能够编写正确格式的XML.
了解XML的约束.
掌握XML的解析.
熟练掌握并使用tomcat发布一个web应用
了解HTTP协议及掌握HTTP协议中的常用的头信息.
使用XML作为配置文件的方式完成模拟Tomcat.
现在有一套页面,这套页面想被其他人访问到.端口号可以进行修改的-(不修改源码的基础上).
XML的概述
可扩展标记语言
可扩展标记语言,标准通用的标记语言的子集,是一个用于标记电子文件使其具有机构性的标记语言。
在电子计算机中,标记值计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的yuan语言。它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是internet环境中夸平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。
什么是XML
XML 指可扩展标记语言(Extensible Markup Language)
XML 是一种标记语言,很类似HTML
XML 的设计宗旨是传输数据,而非显示数据
XML 标签没有被预定义。您需要自定义标签。
XML 被设计为具有自我描述性。
XML 是W3Cde 推荐标准
允许用户自定义标签的!!!
XML的作用:
传输 和 存取数据.
软件的配置文件.
XML的基本语法:
XML必须有关闭标签
区分大小写
属性需要有引号
标签必须正确嵌套.
XML的文档声明
文档声明:通常出现在XML的第一行第一列的位置!!!
写法:
<?xml 属性名=“属性值” 属性名=“属性值”。。。?>
verson="1.0"
encodeing:字符集
<?xml 属性名=”属性值” 属性名=”属性值” ...?>
version :必须的. 使用”1.0”
encoding :字符集. 是使用浏览器打开的时候采用的默认的字符集的编码.
standalone :描述XML文档是否需要依赖其他的文件.
XML的注释
<!-- XML的注释 -->
XML的元素
元素(标签)的命名规范:
XML命名规则
XML元素必须遵循以下命名规则:
名称可以含字母、数字以及其他字符
名称不能以数字或者标点符号开始
名称不能以字符“xml”(或者 XML Xml)开始
名称不能包含空格
名称中不能包含冒号(:)
XML的属性
属性的名称规范与元素一致.
属性需要使用引号!
XML的特殊字符和CDATA区
XML的特殊字符:
< < 小于 < > & &apos "
> > 大于
& & 和号
&apos ‘ 单引号
"; " 引号
XML的CDATA区:(CDATA:Character Data)
<![CDATA[ 内容 ]]>
<![CDATA[ 内容 ]]>
XML的解析:从XML文档中获得想要的数据(通过代码完成的.) XML的解析的方式(*****):
DOM解析:DOM:Document Object Model.
SAX解析:Simple Api for XML.
DOM和SAX的区别
DOM:一次性将文档加载到内存,形成数结构进行解析。
缺点:如果文档特别大,容易导致内存的溢出
优点:对XML进行增删改的操作
SAX:事件驱动的方式,一行一行进行解析
优点:不能对文档进行增删改的操作
缺点:如果文档特别大,不会导致内存的溢出。
针对这两种解析的方式,不同的公司提供了不同的API的实现.
JAXP :SUN公司提供的一套XML的解析的API.
JDOM :开源组织提供了一套XML的解析的API-jdom.
DOM4J :开源组织提供了一套XML的解析的API-dom4j.
pull :主要应用在Android手机端解析XML
DOM4J的入门案例步骤;
* 【步骤一】导入jar包.dom4j-1.6.1.jar
* 【步骤二】创建解析器
* 【步骤三】解析文档获得代表文档的Document对象.
* 【步骤四】获得跟节点.
* 【步骤五】从跟节点下查找其他的节点.
@Test
/**
* 获得元素的内容:查询的操作.
*/
public void demo1() throws Exception{
// 创建解析器
SAXReader reader = new SAXReader();
// 解析XML的文档
Document document = reader.read("xml/demo1.xml");
// 获得跟节点
Element root = document.getRootElement();
System.out.println(root.getName());
// 查找跟节点下的子节点. element() elements();
Element pElement = root.element("person"); // 查找的是第一个person元素
// root.elements("person").get(1); // 查找的是第二个person元素
Element nElement = pElement.element("name");
Element aElement = pElement.element("age");
Element sElement = pElement.element("sex");
System.out.println(nElement.getText());
System.out.println(aElement.getText());
System.out.println(sElement.getText());
}
XPath:
* dom4j支持XPath的jar包.
* jaxen-1.1-beta-6.jar
* dom4j的XPath支持的API:
* List document.selectNodes(String xPath);
* Node document.selectSingleNode(String xPath);
* 代码:
@Test
/**
* DOM4J的XPath的写法:
*/
public void demo2() throws Exception{
// 创建解析器:
SAXReader reader = new SAXReader();
// 解析XML返回Document对象.
Document document = reader.read("xml/demo1.xml");
/*List<Node> list = document.selectNodes("//name");
for (Node node : list) {
Element element = (Element) node;
System.out.println(element.getText());
}*/
List<Node> list = document.selectNodes("//person['@id']");
for (Node node : list) {
Element element = (Element) node;
System.out.println(element.attributeValue("id"));
}
}
XML的约束:
XML的约束的额概述:
* 什么是XML的约束 :就是用来约束XML的文档中可以出现哪些标签,不能出现哪些标签,标签中是否有顺序,出现的次数.
* XML的约束 :用来规范XML的写法.
***** XML的约束的种类及区别?
* DTD 和 Schema :
* 区别:
1.DTD语法是自成一体的.Schema语法就是XML的语法.
2.Schema的语法就是XML的语法所以更容易被解析器所解析.
3.Schema支持名称空间.
4.Schema有比DTD更加强大的语义和语法的约束.
DTD的语法 :(了解)
* DTD的引入方式:
* 内部的DTD:
<!DOCTYPE persons [
]>
* 外部的DTD:
* 一种本地DTD:
<!DOCTYPE persons SYSTEM "unknown.dtd">
* 一种网络DTD:
<!DOCTYPE persons PUBLIC "//UNKNOWN/" "unknown.dtd">
* DTD的语法:
* 元素:
* <!ELEMENT 元素名 元素类型>
* 元素类型:
* EMPTY
* ANY
* 子元素
* 是否有序: 使用 逗号(,)或者竖线(|)表示.
* 出现的次数:?:零次或一次 +:一次或多次 *:零次或多次
* PCDATA
* 属性:
* <!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>
* 属性的类型:
* ID类型:表示属性值需要是唯一的.
* CDATA类型:普通的字符串.
* 枚举:
* 属性的约束:
Schema的语法:(了解)
<?xml version="1.0" encoding="UTF-8"?>
<!--
名称空间:一个XML只能引入一个DTD约束文档.使用了Schema约束XML文档,一个XML可以引入多个Schame的约束!!!
如果再多个Schema文档中定义了相同的属性名称 该怎么办?
* 名称空间类似于java中的package.通过名称空间区分 标签或属性来自于哪个文档的!!!通常名称空间唯一的不重复的即可.一般情况下使用一个URL地址表示一个名称空间.
xmlns :xml name sapace .代表当前的文档应用的名称空间.
targetNameSpace :目标名称空间.
elementFormDefault :
-->
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itheima.com/ee25"
elementFormDefault="qualified">
<!-- 复杂标签 -->
<element name="persons">
<!-- 复杂类型 -->
<complexType>
<sequence maxOccurs="unbounded" minOccurs="1">
<element name="person">
<complexType>
<sequence>
<!-- 简单标签 -->
<element name="name" type="string"></element>
<element name="age" type="int"></element>
<element name="sex" type="string"></element>
</sequence>
<attribute name="id" type="string" use="required"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
HTTP的协议的概述
协议:
* 什么是协议:规定双方需要遵守的规则.
HTTP协议:
* 什么是HTTP协议:用来规定浏览器与服务器之前需要遵守的规则
HTTP:
超文本传输协议(HTTP , HyperText Transfer Protocl)是互联网上应用最为广泛的一种网络协议。所有的www文件必须遵守这种标准。
HTTP协议的作用:规范浏览器和服务器之间的数据传递.
HTTP协议的特点:
* 基于请求和响应的模型.
* 必须先有请求后有响应.
* 请求和响应必须成对出现.
* 默认的端口号是80. HTTP协议的版本:
* 1.0 :每次响应后即刻关闭了连接.
* 1.1 :现在使用.不是每次响应后挂断,等待长时间以后没有请求会挂断.
HTTP协议的演示
抓包分析:GET方式:
* 请求部分:
GET /day09/demo1-http/demo2.html?name=aaa&age=23 HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 59176-10011
Referer: http://localhost:8080/day09/demo1-http/demo1.html
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: localhost:8080
DNT: 1
Connection: Keep-Alive
抓包分析:POST方式:
POST /day09/demo1-http/demo2.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 59176-10031
Referer: http://localhost:8080/day09/demo1-http/demo1.html
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 15
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
name=bbb&age=38
* 响应部分:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"145-1461807615933"
Last-Modified: Thu, 28 Apr 2016 01:40:15 GMT
Content-Type: text/html
Content-Length: 145
Date: Thu, 28 Apr 2016 01:43:52 GMT
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Demo2.html</h1>
</body>
</html>
HTTP协议的详解
请求部分
* 请求行
* 提交方式:
* 提交方式有很多,常用的GET和POST:
* GET和POST的区别:
* GET的提交的参数会显示到地址栏上,而POST不显示.
* GET往往是有大小限制的,而POST没有大小的限制.
* GET没有请求体,而POST有请求体.
* 提交路径:
* 协议版本:
* 请求头
* 都是键值对的形式显示的.一般一个key对应一个value,也有个别的是一个key对应多个value.
* User-Agent :代表浏览器的类型. --- 文件下载:下载中文文件:IE使用URLEncodor进行编码,而Firefox使用Base64编码.
* Referer :代表的是网页的来源. --- 防盗链.
* If-Modified-Since :通常与响应中的头Last-Modified一起使用查找本地缓存.
* 请求体
* 就是POST提交方式的提交的参数.
响应部分
* 响应行:
* 协议版本
* 状态码 :
* 200 :成功
* 302 :重定向
* 304 :查找本地缓存
* 404 :资源不存在
* 500 :服务器内部错误
* 状态码描述
* 响应头:键值对,一般一个key对应一个value,也有一个key对应多个value.
* Last-Modified :与请求中的If-Modified-Since一起使用查找本地缓存.
* Content-Dispostion :文件下载的使用使用的一个头信息.
* Location :重定向的跳转的路径.
* Refresh :定时刷新/定时跳转.
* 响应体:显示浏览器的页面的内容.
Servlet的概述
什么是Servlet:
* 就是一个运行在WEB服务器上的小的Java程序,用来接收和响应从客户端发送过来的请求,通常使用HTTP协议.
* Servlet就是SUN公司提供的一个动态网页开发技术.
Servlet的作用:
* 用来处理从客户端浏览器发送的请求,并且可以对请求作出响应
使用Servlet:
* 编写一个类实现Servlet接口.
* 将编写的这个类配置到服务器中.
Servlet的入门:
* 编写类:
public class ServletDemo1 implements Servlet{
@Override
/**
* 为用户处理请求和响应的方法.
*/
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
res.getWriter().println("Hello Servlet...");
}
...
}
* 配置:
<!-- 配置Servlet -->
<servlet>
<!-- Servlet的名称 -->
<servlet-name>test1</servlet-name>
<!-- Servlet的全路径 -->
<servlet-class>com.itheima.a_servlet.ServletDemo1</servlet-class>
</servlet>
<!-- Servlet的映射 -->
<servlet-mapping>
<!-- Servlet的名称 -->
<servlet-name>test1</servlet-name>
<!-- Servlet的访问路径 -->
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
http://ip:port/projectName/ServlerDemo1
* 访问:
http://localhost:8080/day09/ServletDemo1
使用ServletRequest接收参数
String getParameter(String name)
Map getParameterMap()
Enumeration getParameterNames()
String [] getParameterValues(String name)
* String getParameter(String name); ---用于接收一个名称对应一个值的数据.
* String[] getParameterValues(String name);---用于接收一个名称对应多个值的数据.
* Map getParameterMap(); ---用于接收表单中的所有的数据,Map的key是表单提交的参数名称,Map的value是提交参数的值.
* Enumeration getParameterNames() ---用于获取表单中提交的所有的参数的名称.
Servlet的访问流程
Servlet的实现的关系
Servlet :接口
|
GenericServlet :通用的Servlet
|
HttpServlet :HttpServlet
* 编写一个类继承HttpServlet,重写doGet和doPost方法.
* 配置
Servlet的访问流程
先设计数据库的表结构
与之对应的实体
有一些资源需要初始化很豪爽
dyc
3个重点
servler 让servlet在服务启动时创建好应该在.xml的配置文件中的
<servler></servlet>标签中配置
<load-on-startup><load-on-startup>传入正整数,正整数的值越小其优先级别越高
<servlet></servlet>
<load-on-startup></load-on-startup>
url-pattern的配置
1、完全路径 /
2、目录匹配 /*
3、扩展名匹配 .do
********************************************************************************************************
读取WEB工程下的文件
/**
* 传统方式读取文件:
* * 使用的是相对路径,相对的JVM的路径.
* * 但是现在是一个web项目,相对于JVM的路径的.现在JVM已经交给tomcat管理.
* @throws FileNotFoundException
* @throws IOException
*/
private void test1() throws FileNotFoundException, IOException {
InputStream is = new FileInputStream("src/db.properties");
Properties properties = new Properties();
properties.load(is);
String driverClass = properties.getProperty("driverClass");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driverClass);
System.out.println(url);
System.out.println(username);
System.out.println(password);
}
【使用ServletContext对象读取WEB项目下的文件】
InputStream getResourceAsStream(String path)
* InputStream getResourceAsStream(String path); --- 根据提供路径读取文件返回一个文件的输入流.
Strng getRealPath(Sring path)
* String getRealPath(String path); --- 返回一个路径的磁盘绝对路径.
ServletContext的功能:
配置全局初始化参数:
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = this.getServletContext().getInitParameter("username");
String password = this.getServletContext().getInitParameter("password");
System.out.println(username+" "+password);
Enumeration<String> e = this.getServletContext().getInitParameterNames();
while(e.hasMoreElements()){
String name = e.nextElement();
String value = this.getServletContext().getInitParameter(name);
System.out.println(name+" "+value);
}
}
获得文件的MIME的类型
* 获得文件的MIME的类型.
代码实现:
/**
* 获得文件的MIME的类型
*/
private void test2() {
String type = this.getServletContext().getMimeType("1.html");
System.out.println(type);
}
作为域对象存取数据
范围:整个web项目.而且全局的对象.
创建:服务器启动的时候,服务器为每个web项目创建一个单独的ServletContext对象.
销毁:服务器关闭的时候销毁ServletContext.
读取web项目下的文件
Response的概述
Response:代表响应的对象.从服务器向浏览器输出内容
文件下载的方式
一种:超链接下载.直接将文件的路径写到超链接的href中.---前提:文件类型,浏览器不支持.
二种:手动编写代码的方式完成文件的下载.
* 设置两个头和一个流:
* Content-Type :文件的MIME的类型.
* Content-Disposition :以下载的形式打开文件.
* InputStream :文件的输入流.
中文文件的下载
IE浏览器下载中文文件的时候采用的URL的编码.
Firefox浏览器下载中文文件的时候采用的是Base64的编码.
/**
* 文件下载的Servlet
*/
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.接收参数
String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8");
System.out.println(filename);
// 2.完成文件下载:
// 2.1设置Content-Type头
String type = this.getServletContext().getMimeType(filename);
response.setHeader("Content-Type", type);
// 2.3设置文件的InputStream.
String realPath = this.getServletContext().getRealPath("/download/"+filename);
// 根据浏览器的类型处理中文文件的乱码问题:
String agent = request.getHeader("User-Agent");
System.out.println(agent);
if(agent.contains("Firefox")){
filename = base64EncodeFileName(filename);
}else{
filename = URLEncoder.encode(filename,"UTF-8");
}
// 2.2设置Content-Disposition头
response.setHeader("Content-Disposition", "attachment;filename="+filename);
InputStream is = new FileInputStream(realPath);
// 获得response的输出流:
OutputStream os = response.getOutputStream();
int len = 0;
byte[] b = new byte[1024];
while((len = is.read(b))!= -1){
os.write(b, 0, len);
}
is.close();
}
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF-8?B?"
+ new String(base64Encoder.encode(fileName
.getBytes("UTF-8"))) + "?=";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
response输出响应内容的方法:
向页面响应的方法:
* getOutputStream();
* getWriter();
* 这两个方法是互斥的.
* 做出响应的时候只能使用其中的一种流响应.
* 输出中文乱码的处理:
* 字节流:
* 设置浏览器默认打开的编码:
* resposne.setHeader(“Content-Type”,”text/html;charset=UTF-8”);
* 设置中文字节取出的时候编码.
* “中文”.getBytes(“UTF-8”);
* 字符流:
* 设置浏览器打开的时候的编码
* resposne.setHeader(“Content-Type”,”text/html;charset=UTF-8”);
* 设置response的缓冲区的编码
* response.setCharacterEncoding(“UTF-8”);
***** 简化的写法:response.setContentType(“text/html;charset=UTF-8”);
Request的概述
Request代表用户的请求
演示request获得客户机的信息
public class RequestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得请求方式:
String method = request.getMethod();
System.out.println("请求方式:"+method);
// 获得客户机的IP地址:
String ip = request.getRemoteAddr();
System.out.println("IP地址:"+ip);
// 获得用户的请求的路径:
String url = request.getRequestURL().toString();
String uri = request.getRequestURI();
System.out.println("获得请求的URL:"+url);
System.out.println("获得请求的URI:"+uri);
// 获得发布的工程名:
String contextPath = request.getContextPath();
System.out.println("工程名:"+contextPath);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
处理request接收参数的中文乱码的问题
现在无论是GET还是POST提交中文的时候,都会出现乱码的问题.
解决:
POST的解决方案:
* POST的参数在请求体中,直接到达后台的Servlet.数据封装到Servlet中的request中.request也有一个缓冲区.request的缓冲区也是ISO-8859-1编码.
* 设置request的缓冲区的编码:
* request.setCharacterEncoding(“UTF-8”); --- 一定要在接收参数之前设置编码就OK.
GET的解决方案:
* 1.修改tomcat的字符集的编码.(不推荐)
* 2.使用URLEncoder和URLDecoder进行编码和解码的操作.
* 3.使用String的构造方法:
Request作为域对象存取数据:
使用request对象存取数据:
* setAttribute(String name,String value);
* Object getAttribute(String name);
request的作用范围:
* 作用范围就是一次请求的范围.
* 创建和销毁:
* 创建:客户端向服务器发送了一次请求以后,服务器就会创建一个request的对象.
* 销毁:当服务器对这次请求作出了响应之后.
重定向和转发的区别:(redirect和forward的区别)
* 1.重定向的地址栏会发生变化,转发的地址栏不变.
* 2.重定向两次请求两次响应,转发一次请求一次响应.
* 3.重定向路径需要加工程名,转发的路径不需要加工程名.
* 4.重定向可以跳转到任意网站,转发只能在服务器内部进行转发.
******************************************************************************************
Cookie&Session
记录用户的上次登陆访问时间
需求:
用户登录完成后,显示您是第x位访问的用户,您的上次访问时间是:yyyy-MM-dd.
* 如果第一次访问的话,只显示您是第x位用户.
* 如果不是第一次访问的话,显示您是第x位访问的用户,您的上次访问时间是:yyyy-MM-dd.
什么是会话 :用户打开一个浏览器访问页面,访问网站的很多页面,访问完成后将浏览器关闭的过程称为是一次会话.
常见的会话技术:
* Cookie :将数据保存到客户端浏览器.
* Session :将数据保存到服务器端.
为什么使用会话技术?
* 私有的数据,购物信息数据保存在会话技术中.
参见图一和图二
使用会话技术:
Cookie技术的使用
向浏览器保存数据:
HttpServletResponse有一个方法:
* void addCookie(Cookie cookie);
获得浏览器带过来的Cookie:
HttpServletRequest有一个方法:
* Cookie[] getCookies();
创建一个Cookie对象:
* Cookie(String name,String value);
JSP的简单概述
什么是JSP :Java Server Pages(Java服务器端页面).JSP = Java代码 + HTML的元素 + JSP内置东西
SUN公司为什么推出JSP动态网页开发技术:
* SUN公司推出的Servlet技术进行动态网页开发.发现Servlet自身有不足没有办法与ASP,PHP技术竞争.想在动态网页中输出表单.在Servlet中获得PrintWriter out = response.getWriter();
* out.println(“<form action=’’ method=’’>”);
* out.println(“</form>”);
* SUN又推出了动态的网页开发技术就是JSP.
JSP的执行过程:
* JSP会被翻译成Servlet,编译成class进行执行的.
JSP的嵌入Java代码:JSP的脚本元素
* <%! %> :翻译成类中的成员部分. 定义变量,定义方法,定义类.Servlet是线程不安全的,尽量少在类中定义成员属性!!
* <% %> :翻译成类的service方法内部的内容. 定义变量,定义类,直接写代码块.
* <%= %> :翻译成service方法内部的out.print();输出值
步骤分析
【步骤一】:准备登陆的案例.
【步骤二】:在统计人数的Servlet中.判断是否是第一次访问.
【步骤三】:根据是否是第一次显示不同的信息,同时将当前的时候保存到Cookie中
代码实现
public class CountServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
Integer count = (Integer) this.getServletContext().getAttribute("count");
// response.getWriter().println("<h1>现在网站被访问的次数为:"+count+"</h1>");
/**
* 获得浏览器中带过来的所有的Cookie信息,从数组中查找有没有指定名称的Cookie
* 判断用户是否是第一次访问:(从数组中没有找到指定名称的Cookie)
* * 如果是第一次:显示欢迎,记录当前访问的时间存入到Cookie中.
* * 如果不是第一次:显示欢迎,上一次访问时间,同时记录当前访问的时间存入到Cookie中。
*/
// 获得浏览器带过来的所有的Cookie:
Cookie[] cookies = request.getCookies();
// 从数组中查找指定名称的Cookie
Cookie cookie = CookieUtils.findCookie(cookies, "lastVisit");
// 判断是否是第一次:
if(cookie == null){
// 第一次访问
response.getWriter().println("您是第"+count+"位访客!");
}else{
// 不是第一次
Long l = Long.parseLong(cookie.getValue());
Date d = new Date(l);
response.getWriter().println("您是第"+count+"位访客! 上次访问时间是:"+d.toLocaleString());
}
// 创建一个Cookie对象:
Cookie c = new Cookie("lastVisit",""+System.currentTimeMillis());
// 保存到浏览器端:
response.addCookie(c);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Cookie的常用API:
Cookie的常用的API:
* getName();
* getValue();
* setDomain(String domain); -- 设置Cookie的有效域名. // www.baidu.com music.baidu.com
* setPath(String path); -- 设置Cookie的有效路径.
* setMaxAge(int maxAge); -- 设置Cookie的有效时间.
Cookie的分类有关:
* 会话级别的Cookie:默认的Cookie.关闭浏览器Cookie就会销毁.
* 持久级别的Cookie:可以设置Cookie的有效时间.那么关闭浏览器Cookie还会存在. 手动销毁持久性Cookie. setMaxAge(0)---前提是有效路径必须一致
***************************************************************************************************************
Session
将商品添加到购物车:
Session的概述
Cookie本身是有大小和个数的限制.Session没有限制.Cookie的数据保存在客户端,Session数据保存在服务器端.
Session的执行原理:基于Cookie的.
使用Session:
* 获得Session:
* request.getSession();
步骤分析:
【步骤一】:点击加入购物车提交到Servlet
【步骤二】:在Servlet将购物的商品存入到Session中.
【步骤三】:可以创建一个Map集合用于保存购物信息Map的key可以是商品的名称,Map的value是数量.
【步骤四】:在购物车页面中显示Map中的数据就可以.
public class CartServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 接收商品名称:
String name = new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");
// 创建Map集合用于保存购物信息.Map<String,Integer> Map的key是商品的名称 value是购买的数量.
Map<String,Integer> map = (Map<String, Integer>) request.getSession().getAttribute("cart");
if(map == null){
map = new LinkedHashMap<String,Integer>();
}
// 判断购物车中是否已经买了该商品.
if(map.containsKey(name)){
// map中已经有该商品:// * 如果购物车中已经有该商品: 获得到Map中该商品的数量+1。 存回到Map集合中.
Integer count = map.get(name);
count++;
map.put(name, count);
}else{
// map中没有该商品.// * 如果购物车中没有改商品: 将商品添加到Map集合中 数量1.
map.put(name, 1);
}
// * 将Map集合保存到session中.
request.getSession().setAttribute("cart", map);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("<h3><a href='/day11/demo2/product_list.jsp'>继续购物</a> | <a href='/day11/demo2/cart.jsp'>去结算</a></h3>");
}
Session是域对象:
session何时创建和销毁?作用范围:
* 创建:服务器端第一次调用getSession()创建session.
* 销毁:三种情况销毁session:
* 1.session过期. 默认过期时间为30分钟.
* 2.非正常关闭服务器.如果正常关闭session序列化到硬盘.
* 3.手动调用session.invalidate();
* 作用范围:多次请求.(一次会话)
JSP
数据库中存放了很多商品信息,现在将商品的信息全部显示到页面
JSP的概述
什么是JSP:
* Java Server Pages(Java服务器端的页面)
为什么要学习JSP:
* SUN公司推出的Servlet自身有缺陷,没有办法与ASP,PHP进行竞争.推出了动态网页开发技术JSP.
使用JSP:
* JSP = HTML + Java代码 + JSP自身的东西.
执行JSP的过程:
* JSP翻译成Servlet,编译这个Servlet的类,生成class文件.得到执行.
JSP的脚本
<%! %> :翻译成Servlet中的成员内容. 定义变量,方法,类. -- 不建议.
<% %> :翻译成Servlet中service方法内部的内容. 定义类,变量
<%= %> :翻译成Servlet中service方法中out.print();
JSP的注释】-了解
HTML的注释 :<!-- 注释 -->
Java代码的注释 :// 单行注释 /*多行注释*/ /** 文档注释 */
JSP的注释 :<%-- JSP的注释 --%>
JSP的指令
指令的语法:
<%@ 指令名称 属性名称=”属性值” 属性名称=”属性值” ...%>
JSP中有三个指令:page指令, include指令, taglib指令.
JSP中page指令:<%@ page %> -- 设置JSP的.参数
* language :JSP脚本中使用的语言.现在只能写java.
* contentType :设置浏览器打开这个JSP的时候采用的默认的字符集的编码.
* pageEncoding :设置文件保存到本地硬盘,以及生成Servlet后,Servlet保存到硬盘上的编码.
* import :在JSP中引入类对象.但是import可以出现多次.
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
* extends :设置JSP翻译成Servlet后继承的类,默认值:org.apache.jasper.runtime.HttpJspBase,这个值要想修改,这个类必须是HttpServlet的子类
* autoFlush :设置JSP的缓存自动刷出.true:自动刷出.
* buffer :设置JSP的缓冲区的大小,默认8kb.
* session :设置在JSP中是否可以直接使用session对象.默认值是true.
* isELIgnored :设置在JSP中是否忽略EL表达式.默认值是false不忽略.
* errorPage :设置错误友好页面的提示.
* isErrorPage :通过这个设置显示JSP的错误信息.设置JSP的表达式的
* 设置全局的错误友好页面:
* 在web.xml中设置:
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
JSP中的include指令:指示JSP包含其他的页面.
<%@ include file="logo.jsp" %>
<%@ include file="menu.jsp" %>
<h1>BODY部分</h1>
<%@ include file="footer.jsp" %>
JSP中的taglib指令:指示JSP引入标签库.
<%@ taglib uri="标签的URI的路径" prefix="标签的别名" %>
JSP的内置对象(*****)
JSP的内置对象:在JSP中可以直接使用的对象.
JSP中有9大内置对象:
* request HttpServletRequest getParameter(),setAttribute(String name,Object value);
* response HttpServletResponse setHeader(String name,String value);getOutputStream();getWriter();
* session HttpSession setAttribute();getAttribute();
* application ServletContext setAttribute();getAttribute();
* page Object toString();wait();
* pageContext PageContext setAttribute();getAttribute();
* config ServletConfig getServletName();getServletContext();
* out JspWriter write(),print();
* exception Throwable getMessage(),getCause(); 设置isErrorPage=”true”
page内置对象 :真实对象是Object,就是JSP翻译成Servlet后的类的引用.
out内置对象 :out和response.getWriter是不是同一个对象?区别是什么?
* 不是out真实对象JspWriter ,response获得Writer是PrintWriter.
pageContext内置对象 :
* 获得其他的8个内置对象 :编写通用性代码或者框架的时候.
* 向JSP的四个域中存取数据 :
JSP的四个域范围:
* PageScope :当前页面中有效. pageContext PageContext
* RequestScope :一次请求范围. request HttpServletRequest
* SessionScope :一次会话范围. session HttpSession
* ApplicationScope :应用范围 application ServletContext
********************************************************************************************************
在JSP的页面中显示商品的信息.
JSP的概述
什么是JSP:
* Java Server Pages(Java服务器端的页面)
为什么要学习JSP:
* SUN公司推出的Servlet自身有缺陷,没有办法与ASP,PHP进行竞争.推出了动态网页开发技术JSP.
使用JSP:
* JSP = HTML + Java代码 + JSP自身的东西.
执行JSP的过程:
* JSP翻译成Servlet,编译这个Servlet的类,生成class文件.得到执行.
【JSP的脚本】
<%! %> :翻译成Servlet中的成员内容. 定义变量,方法,类. -- 不建议.
<% %> :翻译成Servlet中service方法内部的内容. 定义类,变量
<%= %> :翻译成Servlet中service方法中out.print();
【JSP的注释】-了解
HTML的注释 :<!-- 注释 -->
Java代码的注释 :// 单行注释 /*多行注释*/ /** 文档注释 */
JSP的注释 :<%-- JSP的注释 --%>
【JSP的指令】
指令的语法:
<%@ 指令名称 属性名称=”属性值” 属性名称=”属性值” ...%>
JSP中有三个指令:page指令, include指令, taglib指令.
JSP中page指令:<%@ page %> -- 设置JSP的.
* language :JSP脚本中使用的语言.现在只能写java.
* contentType :设置浏览器打开这个JSP的时候采用的默认的字符集的编码.
* pageEncoding :设置文件保存到本地硬盘,以及生成Servlet后,Servlet保存到硬盘上的编码.
* import :在JSP中引入类对象.但是import可以出现多次.
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
* extends :设置JSP翻译成Servlet后继承的类,默认值:org.apache.jasper.runtime.HttpJspBase,这个值要想修改,这个类必须是HttpServlet的子类
* autoFlush :设置JSP的缓存自动刷出.true:自动刷出.
* buffer :设置JSP的缓冲区的大小,默认8kb.
* session :设置在JSP中是否可以直接使用session对象.默认值是true.
* isELIgnored :设置在JSP中是否忽略EL表达式.默认值是false不忽略.
* errorPage :设置错误友好页面的提示.
* isErrorPage :通过这个设置显示JSP的错误信息.
* 设置全局的错误友好页面:
* 在web.xml中设置:
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
JSP中的include指令:指示JSP包含其他的页面.
<%@ include file="logo.jsp" %>
<%@ include file="menu.jsp" %>
<h1>BODY部分</h1>
<%@ include file="footer.jsp" %>
JSP中的taglib指令:指示JSP引入标签库.
<%@ taglib uri="标签的URI的路径" prefix="标签的别名" %>
【JSP的内置对象(*****)】
JSP的内置对象:在JSP中可以直接使用的对象.
JSP中有9大内置对象:
* request HttpServletRequest getParameter(),setAttribute(String name,Object value);
* response HttpServletResponse setHeader(String name,String value);getOutputStream();getWriter();
* session HttpSession setAttribute();getAttribute();
* application ServletContext setAttribute();getAttribute();
* page Object toString();wait();
* pageContext PageContext setAttribute();getAttribute();
config ServletConfig getServletName();getServletContext();代表当前JSP配置信息,
* out JspWriter write(),print();
* exception Throwable getMessage(),getCause(); 设置isErrorPage=”true”
page内置对象 :真实对象是Object,就是JSP翻译成Servlet后的类的引用.
out内置对象 :out和response.getWriter是不是同一个对象?区别是什么?
* 不是out真实对象JspWriter ,response获得Writer是PrintWriter.
pageContext内置对象 :
* 获得其他的8个内置对象 :编写通用性代码或者框架的时候.
* 向JSP的四个域中存取数据 :
JSP的四个域范围:
* PageScope :当前页面中有效. pageContext PageContext
* RequestScope :一次请求范围. request HttpServletRequest
* SessionScope :一次会话范围. session HttpSession
* ApplicationScope :应用范围 application ServletContext
【JSP的动作标签】列出6个.
标签的作用:简化代码.
<jsp:forward /> :用于页面的转发.
* <jsp:forward page="/demo1-jsp/demo3-object/demo3.jsp"></jsp:forward>
<jsp:include /> :用于页面的包含.(动态包含)
*****静态包含和动态包含的区别?(<%@ include%>和<jsp:include>)
<jsp:param /> :用于带有路径的标签下,传递参数.
<jsp:useBean /> :用于在JSP中使用JavaBean.
<jsp:setProperty /> :用于在JSP中向JavaBean设置属性的.
<jsp:getProperty /> :用于在JSP中获得JavaBean的属性.
EL表达式:
EL(Expression Language)目的:为了使JSP写起来更加简单。表达式语言的灵感来自于ECMAS
语言,它提供了在JSP 中的简化表达式的方法
为什么学习EL:
* 简化JSP的代码,而且减少<%%>
使用EL表达式:
* 语法:${ EL表达式 }
EL的功能:
* 获取数据:(JSP的四个域)
* 执行运算:
* 操作WEB开发的常用的对象:
* 调用Java中方法:--很少用.
EL获取数据
<h3>存取是普通的单值数据</h3>
<%
//pageContext.setAttribute("name", "pValue");
//request.setAttribute("name", "rValue");
//session.setAttribute("name", "sValue");
application.setAttribute("name", "aValue");
%>
<%=pageContext.getAttribute("name") %> <!-- 如果没找到 返回null -->
<%=request.getAttribute("name") %>
<%=session.getAttribute("name") %>
<%=application.getAttribute("name") %>
<hr/>
${ pageScope.name } <!-- 返回的是"" -->
${ requestScope.name }
${ sessionScope.name }
${ applicationScope.name }
<hr/>
${ name } <!-- 类似findAttribute("name") 先从page域中查找,没找到去request域中查询,没有找到去session域中找,没有找到就去application域中找 -->
<h3>获取数组的数据</h3>
<%
String[] arrs = {"李旭华","李冠希","杨凤","杨如花"};
pageContext.setAttribute("arrs", arrs);
%>
${ arrs[0] }
${ arrs[1] }
${ arrs[2] }
${ arrs[3] }
<h3>获取List集合的数据</h3>
<%
List<String> list = new ArrayList<String>();
list.add("李芙蓉");
list.add("杨芙蓉");
list.add("王凤");
pageContext.setAttribute("list", list);
%>
${ list[0] }
${ list[1] }
${ list[2] }
<h3>获取Map集合的数据</h3>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("aaa","李旭华");
map.put("bbb","杨久君");
map.put("ccc","李芮");
map.put("ddd","李凤");
pageContext.setAttribute("map", map);
%>
${ map.aaa }
${ map.bbb }
${ map.ccc }
${ map.ddd }
<h3>获取对象的数据</h3>
<%
User user = new User(1,"aaa","123");
pageContext.setAttribute("user", user);
%>
${ user.id }
${ user.username }
${ user.password }
<h3>获取对象的集合的数据</h3>
<%
User user1 = new User(1,"aaa","123");
User user2 = new User(2,"bbb","123");
User user3 = new User(3,"ccc","123");
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
pageContext.setAttribute("userList", userList);
%>
${ userList[0].id } - ${ userList[0].username } - ${ userList[0].password }<br/>
${ userList[1].id } - ${ userList[1].username } - ${ userList[1].password }<br/>
${ userList[2].id } - ${ userList[2].username } - ${ userList[2].password }<br/>
***** .和[]的区别.
* []用于有下标的数据(数组,list集合) .用于有属性的数据(map,对象)
* 如果属性名中包含有特殊的字符.必须使用[]
【EL执行运算】
<h1>EL的功能二:执行运算</h1>
<h3>EL执行算数运算</h3>
<%
pageContext.setAttribute("n1", "10");
pageContext.setAttribute("n2", "20");
pageContext.setAttribute("n3", "30");
pageContext.setAttribute("n4", "40");
%>
${ n1 + n2 + n3 }
<h3>EL执行逻辑运算</h3>
${ n1 < n2 } - ${ n1 lt n2 } <!-- less than --><br/>
${ n1 > n2 } - ${ n1 gt n2 } <!-- great than --><br/>
${ n1 <= n2 } - ${ n1 le n2 } <!-- less equal --><br/>
${ n1 >= n2 } - ${ n1 ge n2 } <!-- great equal --><br/>
${ n1 == n2 } - ${ n1 eq n2 } <!-- equal --><br/>
<h3>EL执行关系运算</h3>
${ n1<n2 && n3 < n4 } - ${ n1<n2 and n3 < n4 }<br/>
${ n1<n2 || n3 < n4 } - ${ n1<n2 or n3 < n4 }<br/>
${ !(n1 < n2) } - ${ not(n1<n2) }
<h3>EL执行三元运算</h3>
${ n1 < n2 ? "正确":"错误" }
<h3>empty运算</h3>
${ user == null } - ${ empty user }
${ user != null } - ${ not empty user }
【EL操作WEB开发的常用对象11个】
<h1>EL功能三:操作WEB开发常用的对象</h1>
<!--
pageScope,requestScope,sessionScope,applicationScope - 获取JSP中域中的数据
param,paramValues - 接收参数.
header,headerValues - 获取请求头信息 initParam - 获取全局初始化参数
cookie - WEB开发中cookie
pageContext - WEB开发中的pageContext.
-->
<h3>接收请求的参数</h3>
<%= request.getParameter("id") %>
<%= request.getParameter("name") %>
<%= Arrays.toString(request.getParameterValues("hobby")) %>
<hr/>
${ param.id }
${ param.name }
${ paramValues.hobby[0] }
${ paramValues.hobby[1] }
<h3>获取请求头</h3>
<%= request.getHeader("User-Agent") %>
<hr/>
${ header["User-Agent"] }
<h3>获取全局初始化参数</h3>
${ initParam.username }
<h3>获取Cookie中的值</h3>
${ cookie.history.value }
<h3>获取PageContext中的对象</h3>
IP地址:${ pageContext.request.remoteAddr }
工程路径:${ pageContext.request.contextPath }
JSTL
JSTL的概念
(JSP Standar Tag Library ,jsp的标准库)是一个不断完善开饭源码的JSP标签库
为什么学习JSTL:
* JSTL和EL结合 替换页面中<%%>
JSTL版本:
* JSTL1.0 :不支持EL表达式.
* JSTL1.1 和 1.2 :支持EL表达式.
JSTL的标签库:包含了五类标签.
* core(核心标签),fmt(国际化标签),xml(XML标签),sql(SQL标签),fn(JSTL提供EL函数库)
使用JSTL:
* 引入JSTL的相关的jar包.
* 在页面中引入标签库.<%@ taglib uri=”” prefix=””%>
JSTL的核心标签的用法
* if
* forEach
JSTL的提供EL的函数库
<h1>JSTL提供的EL的函数库</h1>
${ fn:contains("Hello World","Hello") }
${ fn:length("HelloWorld") }
${ fn:toLowerCase("ABCDE") }
<c:forEach var="i" items='${ fn:split("a-b-c-d","-") }'>
${ i }
</c:forEach>
<c:forEach var="i" items="${fn:split(a-b-c-d)},"-">
${i}
</c:forEach>
JSTL的遍历用<froEach var="",items="${list}"></forEach>
<c:froEach var="1" itmes="${list}">
<tr>
<td>${p.pid}</td>
<td>${p.pname}</td>
<td>${p.shop_price}</td>
<td>
<c:if test="${p.is_hot==1}">是</c:if>
</td>
<td>
<c:if test="${p.is_hot!=1}"></c:if>
</td>
<>
</tr>
<c:forEach>
|