前端+数据库

数据库的概述

什么是数据库

数据库:简而言之,就是存储数据,管理数据的仓库。

根据数据库底层结构的不同,数据库可以分为很多种类:

  • 层次式数据库
  • 网络式数据库
  • 关系型数据库(市场主流)
  • 非关系型数据库

关系型数据库

以二维表的形式保存数据的数据库就是关系型数据库,例如:

Studentnameagescore
1张三1898
2李四1787
3王五1985

提示:非关系型数据库底层是键值对结构(如HashMap)

名字解释

  • 数据库服务器:就是一个软件,比如mysql的安装软件,或者Oracle的安装软件等,将软件安装在服务器上(计算机),就可以提供服务了
  • 数据库:一个数据库服务器中,可以创建多个数据库,一般情况下,一个网站中的所有数据会存放在一个数据库中。(即一个网站对应一个数据库
  • 数据表/表:一个数据库中,可以创建多张表,一般情况下,一张表中用于存放一类信息。比如:将所有的用户信息存放在user表中,将所有的商品信息存放在product中。(即一类信息(class)对应一张表
  • 表记录:一张表中,可以有多行表记录,一般情况下,某一个具体的信息会存放到一行表记录中(即某一个具体的信息(对象)对应一行表记录

mysql服务器

指令

  • 进入mysql服务器:win + r — cmd — mysql -uroot -proot(mysql + u + 用户名 + p + 用户密码)

  • 查看服务器中所有的数据库:show databases;

  • 进入某一数据库(进入数据库后,才能操作库中的表和表记录):use + 数据库名;(如:use mysql;)

  • 查看某个数据库下所有的数据表:show tables;

  • MariaDB [(none)]>:表示没有进入数据库

  • MariaDB [mysql]>:表示进入mysql数据库

  • 切换到其它数据库:use + 数据库(不需要先退出当前数据库)

  • Empty set:没有表

  • 查看已进入的库:select database();

  • 删除mydb1库:drop database mydb1;(避免错误产生:drop databse if exists mydb1;

  • 创建新库:create database 库名 charset 编码; 如重新创建mydb1库,指定编码为utf8:create database mydb1 charset utf8;(mysql中不承认utf-8)。注意:如果后面没有指定编码,将会使用默认的编码(iso8859-1(无中文)),因此一定要指定编码!避免错误产生:create database if not exists mydb1 charset utf8;

  • 查看建库时的语句(并验证数据库使用的编码):show create database 库名;如:show create database mydb1;

  • SQL语句三种注释方式:

    • /* 注释内容,不会执行 */
    • # 注释内容,不会执行
    • – 注释内容,不会执行
  • 进入库,删除表:drop table 表名;如:进入mydb1库,删除stu学生表(如果存在),use mydb1;drop table if exists stu;

  • 建表:create table 表名(

    列名 数据类型,

    列名 数据类型,

    );

    如创建stu表:(if not exists 可不加)
    create table if not exists stu(

    id int,

    name varchar(50),

    gender varchar(2),

    birthday date,

    score double

    );

  • 查看表的数据结构

    • 查看建表时的语句:show create table 表名
    • 查看表结构:desc 表名
  • 往表中插入数据:insert into 表名(列1,列2,列3…) values(值1,值2,值3…);

    例如:

    insert into stu(id,name,gender,birthday,score) values(1,‘wht’,‘1’,‘1988-6-9’,80);

    insert into stu values(2,‘lpx’,‘0’,‘1987-4-5’,88);//插入全部列数据时,可以省略前面的列项

    insert into stu values(3,‘林’,‘男’,‘1996-4-9’,90);

    注意:字符串或日期需要用单引号’'

  • 查询表格中所有信息:select * from 表名;

    使用 * 的缺点:把不需要的列也列出来,会降低查询效率,如无需全部列出,可指定列名查询,如select dept,job from emp;

    如果查询结果中,存在大量重复记录,可以用distinct剔除,如select distinct dept,job from emp;

    如果查询结果中存在null值,可用ifnull函数替换null,格式:ifnull(列,值); 如:a,b为列,b中存在null值,要替换成0做运算:select a+ifnull(b,0) from 表名 where a+ifnull(b,0);

  • 修改表中列的值:update 表名 set 列=值,列=值,列=值…; 如修改stu表中所有学生的成绩,update stu set score=score+10;;如需指定修改某个成绩,可以写成update stu set score=score+10 where name = ‘xxx’;

  • 删除表记录:

    • 删除所有记录:delete from 表名
    • 删除符合条件的记录:delete from 表名 where 条件
    • 删除重建表:truncate table stu;
  • 筛选掉符合条件的记录:

    • select * from 表名 where 列名 != 值 and 列名 != 值…
    • select * from 表名 where not (列名 = 值 or 列名 = 值…)
    • select * from 表名 where 列名 not in(值1,值2,值3…)
  • 筛选null值:select * from 表名 where 列名 is null;

  • 查询以某个字为开头的内容:select * from 表名 where 列名 like ‘xxx%’,百分号可以通配0或多个字符,如查询姓刘的员工:select * from emp where name like ‘刘%’;

  • 查询以某个字为开头,并且字数确定的内容,用下划线_代表字数,一条下划线代表一个字符。select from 表名 where 列名 like ‘xxx_’,如:如查询姓刘且名字为1个字的员工:select * from emp where name like ‘刘_’;

  • 查询表中包含某个字符的内容,select * from 表名 where 列名 like %xxx%;

  • 分组查询:select * from emp group by 列名,按照列进行分组,count(列名):查询列中各项的个数

  • 求某条件下符合的个数:select count(列名或*) from 表名 where 条件;

  • 统计总和:select sum(统计列列名名) from 表名;

  • 求平均值:select avg(列名) from 表名

  • year(),month(),day():用于获取日期中的年月日

  • 对某列进行升序排序:select * from 表名 order by 列名 + (asc),asc可省略

  • 对某列进行降序排序:select * from 表名 order by 列名 desc;

  • 分页查询:limit (页码-1)*每页显示记录数,每页显示记录数。如查询emp表中所有的记录,分页显示:每页显示3条记录,返回第1页:select * from emp limit 0,3;(页码-1)*每页显示记录数 = (1-1)* 3 = 0

  • 查询表之间的对应关系:select * from 表1,表2 where 表1.列1=表2.列2,如:select * from dept,emp where dept_id=dept.id;

    笛卡尔积查询:select * from dept,emp;查询的行数是两个表的行数相乘

    关联查询:在笛卡尔积查询的基础上,通过关联条件,剔除错误的数据,保留正确数据。select * from dept,emp where dept.id=dept_id;

    左边连接查询:select * from 左边表 left join 右边表 on 关联条件… 左边连接查询,会把左边表的数据全部查出来,而右边表只查出对应关系的数据

    右边连接查询:select * from 左边表 right join 右边表 on 关联条件… 右边连接查询,会把右边表的数据全部查出来,而左边表只查出对应关系的数据

  • 子查询:所谓的子查询,其实就是将一个查询得出的结果,作为另外一个查询的条件。如select * from emp where (select sal from emp where name=‘Lin’)< sal;

  • 列出薪资比‘大数据’部门(已知部门编号30)所有的员工薪资都高的员工信息,显示姓名、薪资和部门名称

    求出大数据部门的最高薪资

    select max(sal) from emp where dept_id=30;

    使用右外连接查询,查询所有员工及其对应部门

    select emp.name,sal,dept.name from dept right join emp on dept.id=dept_id;

    求出薪资比‘大数据部门最高薪资’还高的员工信息

    select emp.name,sal,dept.name from dept right join emp on dept.id=dept_id where sal > (select max(sal) from emp where dept_id=30);

  • 列出在‘培优部’任职的员工,假定不知道‘培优部’的部门编号,显示部门名称,员工名称

    关联查询两张表

    select d.name,e.name from dept d,emp e where e.dept_id=d.id;

    求出在培优部的员工

    select d.name,e.name from dept d,emp e where e.dept_id=d.id and d.name=‘培优部’;

  • (自查询)列出所有员工及其直接上级,显示员工姓名、上级编号、上级姓名

    要查询的表:

    emp e1 员工表

    emp e2 上级表

    关联条件:e1.topid=e2.id

    要显示的列:e1.name,e2.id,e2.name

    select e1.name,e2.id,e2.name from emp e1,emp e2 where e1.topid=e2.id;

  • 列出最低薪资大于1500的各种职位,显示职位和该职位最低薪资

    求出各个职位的最低薪资

    select job, min(sal) from emp group by job;

    筛选最低薪资大于1500的职位有哪些

    select job,min(sal) from emp group by job having min(sal) > 1500;

  • 列出在每个部门就职的员工数量、平均工资。显示部门编号、员工数量,平均薪资

    select dept_id 部门编号,count(*) 部门人数,avg(sal) 平均薪资 from emp group by dept_id;

  • 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数

    关联查询两张表(dept、emp)

    select d.id,d.name,d.loc,count(*) from dept d,emp e where d.id=e.dept_id group by d.name;

  • 列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称

    列:e1.id,e1.name,d.name

    表:emp e1,emp e2,dept d

    关联条件:e1.topid=e2.id e1.dept_id=d.id

    筛选条件:e1.hdate<e2.hdate

    select e1.id,e1.name,d.name from emp e1,emp e2,dept d where e1.topid=e2.id and e1.dept_id=d.id and e1.hdate<e2.hdate;

  • 列出每个部门薪资最高的员工信息,显示部门编号、员工姓名、薪资

    查询emp表中所有员工的部门编号、姓名、薪资

    select dept_id,name,sal from emp;

    查询emp表中每个部门的最高薪资,显示部门编号、最高薪资

    select dept_id,max(sal) from emp group by dept_id;

    第二次查询的结果作为一张临时表和第一次查询进行关联查询

    select emp.dept_id,emp.name,sal from emp,(select dept_id,max(sal) maxsal from emp group by dept_id;) t1 where t1.maxsal=emp.sal and t1.dept_id=emp.dept_id;

Mysql数据类型

MySQL中提供了很多数值类型,和java中的数值类型可以一一对应,但是常用的数值类型是int和double

MysqlJava
tinyintbyte
smallintshort
intint
doubledouble
varchar(char)String

字符串类型

Mysql中提供的字符串类型有两种,分别是char和varchar类型

  • char(n):定长字符串,范围n:小于等于255个字符,不足n个字符以空格补全,可能会造成一定的空间浪费,效率上会比varchar略高一些

    因此,char类型适合存储长度固定的数据,这样既不会有空间浪费,效率上还会更高一些

  • varchar(n):不定长字符串,不足n个字符的不作补全,因此不会造成空间浪费,效率略低

    • mysql5.0之前版本:范围n:小于等于255个字符
    • mysql5.0之后版本:varchar类型的列不超过65535个字节,其中n仍然指定字符数

    因此,varchar类型适合存储长度不固定的数据,虽然效率会比char类型略低,但是不会有空间的浪费

日期类型

  • date:日期,格式:年月日
  • time:时间,格式:时分秒
  • datetime:日期+时间,格式:年月日 时分秒
  • timestamp:时间戳,格式:年月日 时分秒

timestamp和datetime的区别?

相同点:都是日期类型,显示格式都是年月日 时分秒

不同点:

  • datetime表示日期+时间,存储内容和显示内容是相同的
  • timestamp表示日期+时间,存储的实际上是从1970年1月1日到指定日期之间的毫秒值
  • 范围不同,datetime的范围是1000~9999(年份),timestamp的范围是1970~2038(年份)
  • 应用场景不同:timestamp可以自动更新时间为当前时间,datatime不可以

例:

stuidnameagescorecreatetimetimestamp
1张三1898手动插入自动插入
2李四1787手动插入自动插入
3王五1985手动插入自动插入

上表中,如果时间格式为createtime格式,则不会自动更新时间,需要手动插入;而如果为timestamp格式,则会自动更新为当前时间

新增、修改、删除表记录

通过cmd插入或查询数据的编码问题:

  • 插入数据乱码问题,解决方案:

    1. 确认所插入的数据库的编码,在建库时是否指定为utf8,查看建库时的语句:show create database 库名

      如果建库时,没有指定编码,默认编码是latin1,而latin1没有中文,所以在存储中文数据时,必然会出现乱码问题,因此需要将库删除重建,重建时,指定编码为utf8,例如:create database 库名 charset utf8;或者直接修改数据库的编码为utf8:alter database 库名 charset utf8;

    2. 如果上面的确认库的编码是utf8,在插入数据之前,在cmd中,需要先设置一个编码:set names GBK;再插入数据。

      需要注意的是:set names GBK;这条命令只对当前窗口有效,所以下次再开启别的窗口仍然需要设置

三种约束

主键约束

如果将列设置为主键,即添加主键约束,则这一列的值既不能重复也不能为空,只有主键可以设置递增

如果id添加了主键约束,可以设置id为主键自增,这样数据库在表中保存一个自增变量,变量的值从1开始,数据库会帮我们插入id的值,每次插入值后,自增1。

添加主键约束:

create table if not exists 表名(
    # 添加主键约束
    列名 数据类型 primary key,
    # 添加主键约束并设置为主键自增
    列名 数据类型 primary key auto_increment,
    ...
);

设置自增后,在插入数据时,仍可以指定值,但是,新插入的值会根据原来表格中的最大值作递增

唯一约束

如果为某一列添加唯一约束,则该列的值不能重复(但可以为空)

添加唯一约束:

create table if not exists 表名(
    列名 数据类型 unique,
    ...
);

非空约束

如果为某一列添加非空约束,则这一列的值不能为空(但可以重复)

添加唯一约束:

create table if not exists 表名(
    列名 数据类型 not null,
    ...
);

drop 、delete和truncate的区别

drop用于删除库和表,和删除表记录没有关系

delete和truncate都是用于删除表记录。

  • delete删除表记录,可以通过where进行筛选,只删除符合条件的记录,但truncate是删除整张表,不能删除一部分。
  • delete也可以删除所有记录,但是不能重置自增变量,即使删除所有的表记录,下次插入数据时,自增变量依旧照以前自增。而truncate是删除整张表再重建,id自增会从1开始记录

mysql中常见的函数

  • ifnull:用于对某一列进行判断,如果这一列中有null值,可以指定值对null值进行替换。

    格式:ifnull(列,值);

    select name,sal+ifnull(bonus,0) from emp where sal+ifnull(bonus,0) > 3500;
    
  • as:指定别名,可省略

    格式:列名 as 别名

    select name as 姓名,salary 薪资 from emp where salary > 3500;
    
    

– where子句中不能使用列别名,但可以使用表别名
如:
select e.name,e.sal from emp e where e.sal > 3000;

select name,sal from emp where sal in(1400,1600,1800) 等价于 select name,sal from emp where sal = 1400,sal = 1600,sal = 1800;

  • count():对查询的结果统计行数
  • year(date) month(date) day(date) 获取日期中的年月日
  • curdate():获取当前日期 年月日
  • curtime():获取当前时间 时分秒
  • sysdate():获取当前日期+时间 即年月日 时分秒
  • max():求某一列的最大值
  • min():求某一列的最小值
  • avg():求平均值

外键

所谓的外键,就是用于通知数据库中两张表列和列之间的对应关系,并且可以让数据库帮我们维护这段关系的列就叫做外键

用来保存数据库中两张表的对应关系,可以在一张表中指定另一张表的主键为外键(当然也可以不指定)。指定了外键,数据库知道两张表之间的关系并帮我们维护,若不指定,需要人为维护。

image-20210218230919667

where 和 having 的区别

where 和 having 都是用于筛选过滤, 但是使用场景不同

  • where 是对分组之前的数据进行筛选过滤
  • having是对分组之后的数据进行筛选过滤
  • where 中不能使用列别名和聚合函数(max/min/sum/avg/count)
  • having中可以使用列别名和聚合函数
  • 如果where和having不是同时出现,大多数情况下,having可以替代where,但是反过来不行!

表关系

一对多、多对一

对于一对多或者多对一的关系:可以在多的一方添加列,保存一的以访的主键,从而来保存两张表之间的对应关系

一对一

针对一对一的关系:可以在任意一张表中添加列来保存另外一张表的主键,从而来保存两张表的对应关系

多对多

对于多对多的关系,不能在任何一方添加列的保存关系,但可以添加一个第三方的表,在第三方表中分别保存两张表的主键,以此来保存两张表中数据之间的对应关系

备份数据库

在cmd窗口中(未登录状态),通过mysqldump命令备份数据库:

举例:备份db30库中所有数据(dept表及其中的记录和emp表及其中的记录),将数据备份到d:/db40.sql文件中

格式:mysqldump -u用户名 -p 备份的库的名字 > 备份文件位置

mysqldump -uroot -p db30 > d:/db30.sql

恢复数据库

在cmd窗口中(未登录状态),通过mysql命令恢复数据库:

格式:mysql -u用户名 -p 恢复到数据库的名字 < 备份文件的位置

举例:上面备份了db30库中的数据,将备份的db30库中的数据恢复到db80中

第一种方式:

mysql -uroot -p db80 < d:/db30.sql  -- 需要先建好db80库

第二种方式:

source d:/db30.sql;

数据乱码问题

image-20210223230406247

设置默认编码

修改C:\Program Files\MariaDB 10.5\data 目录下的my.ini

image-20210223231526966

重启服务器命令:

停止服务器:net stop mysql

重启服务器:net start mysql

重置eclipse

Window – Perspective – Reset Perspective

JDBC

概念

JDBC:Java DataBase Connectivity java数据库连接

其实就是利用java语言/java程序连接并访问数据库的一门技术

之前我们会通过cmd窗口或者其他第三方的软件(navicat)等连接并访问数据库,但是在企业开发中,我们更多的时通过程序(java程序)连接并访问数据库

利用java程序访问数据库就必须用到JDBC这门技术

本机地址:localhost或127.0.0.1

image-20210224201431121

jdbc连接访问数据库:

  1. 注册数据库驱动(将mysql驱动包交给jdbc来管理,方便我们使用驱动包中的API)

    Class.forName("com.mysql.jdbc.Driver");
    

    之前我们通过DriverManager.registerDriver( new Driver() );这种方法注册驱动,但这种方法有两个不好的地方:

    • 会导致驱动注册两次
    • 会让程序和具体的驱动包绑死在一起(无法导入java.sql包,只能导入com.mysql.jdbc包)。Class.forName(“com.mysql.jdbc.Driver”)中的字符串后期可以提取到配置文件中,不需要重新编译,因此用这种方式注册驱动不会将程序和驱动绑死
  2. 获取数据库连接( Connection);提供传输通道。jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8防止出现中文乱码

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jt_db", "root", "root");
    

    jdbc:mysql://localhost:3306/jt_db 类比 http://www.baidu.com:80/index.html

    协议名 主机名+端口 访问的库名

    如果连接的端口是3306,由于mysql默认端口是3306,所以可以省略不写:jdbc:mysql://localhost/jt_db

    如果连接的是本地的数据库,localhost(127.0.0.1)也可以省略不写:jdbc:mysql:///jt_db

    另外:可以在url后面拼接参数来防止中文乱码问题:jdbc:mysql:///jt_db**?characterEncoding=utf-8**(用程序告诉服务器用utf-8来接收中文数据并告诉服务器用utf-8向java返回数据)

  3. 获取传输器

    Statement stat = conn.createStatement();
    
  4. 利用传输器发送sql到服务器执行,并返回执行结果

    • 使用传输器的executeQuery(sql)方法来查询结果(返回的是查询结果)

    • 使用传输器的executeUpdate(sql)方法来更新值(返回的是作用的行数)

      String sql = "select * from account";//account;后面的分号可不加
      ResultSet rs = stat.executeQuery(sql);
      stat.executeUpdate(sql);
      
  5. 处理结果

    遍历传输器返回的值

    while(rs.next()) {
    	int id = rs.getInt("id");
    	String name = rs.getString("name");
    	double money = rs.getDouble("money");	System.out.println(id+":"+name+":"+money);
    	}
    
  6. 释放资源

    finally {
    			 //6.释放资源
    			if( rs != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					rs.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					rs = null;
    				}
    			}
    			
    			if( stat != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					stat.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					stat = null;
    				}
    			}		
    			
    			if( conn != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					conn.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					conn = null;
    				}
    			}
    		}
    

    案例

    package com.wep;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    /**
     * 实现jdbc的快速入门
     * 通过程序连接jt_db库,查询account表中的所有记录
     * 输出到控制台
     */
    public class JdbcDemo1 {
    	static Connection conn;
    	static Statement stat;
    	static ResultSet rs;
    	public static void main(String[] args) {
    		 try {
    				//1.注册数据库驱动
    				Class.forName("com.mysql.jdbc.Driver");
                 
    				 //2.获取数据库连接( Connection);jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8防止出现中文乱码
    				conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jt_db", "root", "root");
    				
    				 //3.获取传输器
    				stat = conn.createStatement();
    				
    				 //4.利用传输器发送sql到服务器执行,并返回执行结果
    				String sql = "select * from account";//account;后面的分号可不加
    				rs = stat.executeQuery(sql);
    				
    				 //5.处理结果
    				while(rs.next()) {
    					int id = rs.getInt("id");
    					String name = rs.getString("name");
    					double money = rs.getDouble("money");
    					System.out.println(id+":"+name+":"+money);
    				}
    				
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			 //6.释放资源
    			if( rs != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					rs.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					rs = null;
    				}
    			}
    			
    			if( stat != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					stat.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					stat = null;
    				}
    			}		
    			
    			if( conn != null) {//如果第三步出现异常,那么第四步无法获得对象,为null值
    				try {
    					conn.close();
    				} catch (SQLException e) {
    					//关闭资源不成功,执行catch代码,catch里面也可能出现异常,因此在finall强制将将对象置为null值
    					e.printStackTrace();
    				} finally {
    					conn = null;
    				}
    			}
    		}
    	}
    }
    

PreparedStatement对象

在上面的增删改查操作中,使用的是Statement传输器对象,而在开发中我们用的更多的传输器对象是PreparedStatement对,PreparedStatement是Statement的子接口,比Statement更加安全,并且能够提高程序执行的效率

用户登录

package com.wep.ps;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
import com.wep.JdbcCRUD;
import com.wep.util.JDBCUtil;
/**
 * 模拟用户登录
 */
public class LoginUser {
	 public static void main(String[] args) {
		 Scanner in = new Scanner(System.in);
		//1.提示用户登录
		 System.out.println("请登录:");
		//2.提示用户输入用户名
		 System.out.println("请输入用户名:");
		 String user = in.nextLine();
		//3.提示用户输入密码
		 System.out.println("请输入密码:");
		 String pwd = in.nextLine();
		//4.调用方法根据用户名和密码进行登录
		 loginUser(user,pwd);
	}

	 /** 根据用户名和密码查询用户信息 */
	private static void loginUser(String user, String pwd) {
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null;
		try {
			//注册服务器驱动并连接服务器
			conn = JDBCUtil.getConn();
			//获取传输器
			stat = conn.createStatement();
			//通过传输器发送sql语句,并返回执行结果
			String sql = "select * from user where username='"+user+"' and password='"+pwd+"'";
			System.out.println(sql);
			rs = stat.executeQuery(sql);
			if(rs.next()) {
//				String username = rs.getString("username");
//				String password = rs.getString("password");
				System.out.println("登录成功!");
			} else {
				System.out.println("登录失败,用户名或密码错误!");
			}	
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(conn, stat, rs);
		}
		
	}
}

SQL注入攻击

上述案例中,如果用户名输入 : 张飞’ # ’ 或者 张飞 ’ or ’ ,不输入密码,都可以登录成功,原因是sql语句被篡改了。

SQL注入攻击产生的原因:由于发送给服务器的sql语句是拼接而来的,其中的参数是用户提交过来的,如果用户在提交参数时,在参数中添加了一些关键字或者特殊符号,就可能会导致sql语句语义(骨架)发生变化,从而导致一些意外的操作!!(比如在不知道用户名或者密码的情况下也能登录成功)

防止SQL注入攻击

防止sql注入攻击的方式不止一种,比如我们可以通过正则表达式对用户提交的参数进行校检,如果发现其中有#或者or等关键字,就提示用户名或密码输入不合法,并结束程序执行

或者更加简便的做法是,通过JDBC自带的PreparedStatement对象也可以防止SQL注入攻击

PreparedStatement对象防止SQL注入攻击的原理是:

PS对象在发送sql语句时,是将sql骨架和sql语句中的参数分开发送,先将sql骨架发送给服务器进行编译并确定下来:

String sql = "select * from user where username=? and password=?";//发给服务器时,编译不执行
ps = conn.prepareStatement(sql);

服务器一旦编译sql骨架,就再也不能被随意修改了,后面再将sql中的参数也发送给服务器:

//设置参数
ps.setString(1, user);
ps.setString(2, pwd);

由于骨架已经被确定了,所以再传过来的参数中即使有sql关键字(#或者or等)也不会影响sql骨架,只会被当作普通的文本来执行!

数据库连接池(DataSource)

什么是连接池

常量池、线程池、连接池

池:是指内存中的一片空间,可以理解为是一个容器

连接池:就是将一批连接存放在一个容器中,供整个程序共享。这样可以减少连接创建和关闭的次数,提高程序的效率,实现连接的复用

image-20210228235520669

传统方式每次需要连接就创建连接,用完连接后就关闭连接,而创建连接和关闭连接需要消耗大量的时间和资源,会导致程序效率低下

如何提高程序执行的效率,减少连接创建和关闭的次数,实现连接的复用?

使用连接池操作数据库:
image-20210301000403325

在程序一启动时,就初始化一批连接放在一个池子中,供整个程序共享。当用户访问数据库需要连接时,不要自己创建,而是从连接池中获取一个连接进行使用,当用完连接也不要将连接关闭,而是将连接还回池中,这样一来,既减少了连接创建和关闭的次数,也实现了连接的复用,提高了程序的效率。

为什么要使用连接池

  • 不使用连接池:每次需要连接都创建连接,用完之后就直接关闭,连接没有复用,而且创建和关闭连接需要消耗大量的时间和资源,所以会造成程序效率低下
  • 使用连接池:每次需要连接不用再创建,而是直接从连接池中获取一个连接对象,用完后将连接直接还回连接池中。这样一来减少了连接创建和关闭的次数,实现了连接的复用,提高了程序执行的效率!

如何使用C3P0连接池

使用C3P0开发步骤:

  1. 导入开发包

    image-20210301235611137

  2. 创建数据库连接池

    //创建连接池对象
    ComboPooledDataSource pool = new ComboPooledDataSource();
    
  3. 设置连接数据库的基本信息

    • 方式一:(不推荐)

      //注册驱动
      pool.setDriverClass("com.mysql.jdbc.Driver");
      //传入参数,连接服务器
      pool.setJdbcUrl("jdbc:mysql:///jt_db?characterEncoding=utf-8");
      pool.setUser("root");
      pool.setPassword("root");
      

      上面这种方式是将参数写死在程序中,如果将来参数发生变化,就需要修改程序,程序需要重新编译,项目也需要重新发布,非常麻烦

    • 方式二:(推荐)

      将参数提取到配置文件中,将来即使参数发生了变化,只需要修改配置文件,不需要修改程序,程序也不需要重新编译和发布

      需要注意的是:这种方式,需要在src目录下提供一个名称为c3p0.properties的文件,文件内容配置如下:

      c3p0.driverClass=com.mysql.jdbc.Driver
      c3p0.jdbcUrl=jdbc:mysql:///jt_db?characterEncoding=utf-8
      c3p0.user=root
      c3p0.password=root
      
    • 方式三:(推荐)

      需要注意的是:这种方式,需要在src目录下提供一个名称为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:///jt_db?characterEncoding=utf-8
      		</property>
      		<property name="user">
      			root
      		</property>
      		<property name="password">
      			root
      		</property>
      	</default-config>
      </c3p0-config>
      
    • 将连接还回连接池

      conn.close();

      这行代码可以理解为关连接,也可以理解为关连接。具体要看Connection对象从哪来!

      ​ 如果没用使用连接池,连接是我们自己创建的(DriverManager.getConnection获取的),这样的连接对象是原生的没有被修改过的。这时调用conn.close()方法就是关闭连接

      ​ 但如果连接对象是从连接池中获取的(即conn = pool.getConnection()),这样的连接对象已经被连接池改造了,调用conn.close()方法就是还连接到连接池中!

事务

什么是事务

事务:将一堆的SQL语句绑定在一起执行,要么全都执行成功,要么全都执行失败!(有一个失败就算失败)

到网上买东西:下订单到支付,对数据库中数据的影响:

  1. 在订单中会多一个订单记录
  2. 同时会修改商品的库存数量

再比如,转账:A转账给B 100元,需要操作账户表(acc):

  • 开启事务

update acc set money=money-100 where name=‘A’;

update acc set money=money+100 where name=‘B’;

  • 提交事务/回滚事务

转账过程中执行的sql语句应该在一个事务中,要么全部成功,要么全部失败

事务的四大特性

  • 原子性:事务中的所有操作(或者所有要执行的sql语句)都是一个整体,不能再分割。(也就是说,事务中的sql语句,要么全执行成功,要么全执行失败,不存在一部分执行成功,一部分执行失败!)

  • 一致性:事务前后的业务数据总和是保持一致或是保持不变的!

    以转账例,A和B账户各1000元,转账之前的账户金额之和是2000元,只要转账操作在一个事务中,不管最后转账成功与否,最后两个人的账户金额之和肯定还是2000元。

  • 隔离性:事务之间是完全隔离开来的,一个事务是看不到另外一个事务中正在进行的操作的。能看到的要么是另一个事务还未开启之前的状态,或者是另一个事务已经结束的状态!

    比如:

    事务1:要查询A和B的账户金额之和

    事务2:正在执行转账操作:A转账给B 500元

    执行事务2:A - 500 = 500,假如此时B还没收到转账,此时B的余额还是1000,这时候事务1如果也在执行,是看不到事务2正在操作的过程的,也就是不会计算出A+B=1500这种结果,事务2所能看到的,是事务1执行前的数据,或者事务2执行后的数据。

    在事务隔离级别非常高的情况下,事务之间是完全隔离的!

  • 持久性:在事务开启后,以及在事务结束前,对数据产生的操作,并不会真的修改数据库中的数据,而是使用日志的形式进行记录,如果最后执行失败了,就清除日志,相当于什么都没有发生。如果最后事务成功,就按照日志的操作对数据的修改永久地保存到硬盘上。

MySQL中的事务

mysql中默认是自动开启事务,自动提交事务的。默认一条sql就是一个事务

如果希望多条sql在一个事务中,我们需要手动开启事务和手动结束事务。

在mysql中开启事务:start transaction;

在mysql中结束事务:

​ 提交事务:commit;

​ 回滚事务:rollback;

以转账为例,A转账100元给B,假设A减去100执行成功了,但是B加上100执行失败了,最后要回滚事务:(回滚后数据库中的数据没有被改变!)

-- 开启事务
start transaction;
-- A减去100元
update acc set money=money-100 where name='A';
-- B加上100元
update acc set money=money+100 where name='B'; 
select * from acc;
-- 回滚事务
rollback;

演示提交事务:(提交后数据库的数据真正被改变!)

-- 开启事务
start transaction;
-- A减去100元
update acc set money=money-100 where name='A';
-- B加上100元
update acc set money=money+100 where name='B'; 
select * from acc;
-- 提交事务
commit;

事务并发读问题

  • 脏读(调低隔离级别,才会出现脏读)

    set tx_isolation=‘read-uncommitted’; – 允许脏读、不可重复读、幻读

    在一个事务中读取到另外一个事务未提交的数据

    事务1:

    ​ update acc set money=money-100 where name=‘A’;;

    ​ update acc set money=money+100 where name=‘B’;

    ​ – 回滚事务

    ​ rollback;

    事务2:

    ​ select * from acc where name=‘B’; – 回滚之前查询

    脏读示例:

    -- 在窗口1中,开启事务,执行A给B转账100元
    set tx_isolation='read-uncommitted'; -- 允许脏读、不可重复读、幻读
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    update acc set money=money-100 where name='A';
    update acc set money=money+100 where name='B';
    
    -- 在窗口2中,开启事务,查询B的账户金额
    set tx_isolation='read-uncommitted'; -- 允许脏读、不可重复读、幻读
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    select * from acc where name='B'; -- 出现脏数据
    
    -- 切换到窗口1,回滚事务,撤销转账操作。
    rollback; -- 回滚事务
    
    -- 切换到窗口2,查询B的账户金额
    select * from acc where name='B';
    

    在窗口2中,B看到自己的账户增加了100元(此时的数据A操作事务并未提交),此种情况称之为"脏读"。

  • 不可重复读

    在一个事务中,读取到另外一个事务已提交的数据

    在一个事务中,两次对同一个数据的查询结果不一致,因为中间有另外的事务做了修改操作。

    不可重复读示例:

    -- 在窗口1中,开启事务,查询A账户的金额
    set tx_isolation='read-uncommitted'; -- 允许脏读、不可重复读、幻读
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    select * from acc where name='A';
    
    -- 在窗口2中,开启事务,查询A的账户金额减100
    set tx_isolation='read-uncommitted'; -- 允许脏读、不可重复读、幻读
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    update acc set money=money-100 where name='A'; -- A账户减去100
    select * from acc where name='A';
    commit; -- 提交事务
    
    -- 切换到窗口1,再次查询A账户的金额。
    select * from acc where name='A'; -- 前后查询结果不一致
    

    在窗口1中,前后两次对同一数据(账户A的金额)查询结果不一致,是因为在两次查询之间,另一事务对A账户的金额做了修改。此种情况就是"不可以重复读"

  • 幻读

    在一个事务中对同一张表的两次查询结果不一致,因为中间有另外的事务做了插入或删除操作!

    事务1:

    ​ – 查询acc表中的记录(查询结果没有id为3的记录)

    ​ select * from acc;

    ​ 此处事务2执行…

    ​ – 插入id为3的记录到acc表中

    ​ insert into acc values(3,‘C’,2000);

    事务2:
    – 插入了id为3的记录

    ​ insert into acc values(3,‘C’,2000);

    幻读示例:

    -- 在窗口1中,开启事务,查询账户表中是否存在id=3的账户
    set tx_isolation='read-uncommitted'; -- 允许脏读、不可重复读、幻读
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    select * from acc where id=3;
    
    -- 在窗口2中,开启事务,往账户表中插入了一条id为3记录,并提交事务。
    -- 设置mysql允许出现脏读、不可重复度、幻读
    set tx_isolation='read-uncommitted';
    use jt_db; -- 选择jt_db库
    start transaction; -- 开启事务
    insert into acc values(3, 'C', 1000);
    commit; -- 提交事务
    
    -- 切换到窗口1,由于上面窗口1中查询到没有id为3的记录,所以可以插入id为3的记录。
    insert into acc values(3, 'C', 1000); -- 插入会失败!
    

    在窗口1中,查询了不存在id为3的记录,所以接下来要执行插入id为3的记录,但是还未执行插入时,另一事务中插入了id为3的记录并提交了事务,所以接下来窗口1中执行插入操作会失败。

    探究原因,发现账户表中又有了id为3的记录(感觉像是出现了幻觉)。这种情况称之为"幻读"

事务的隔离级别(四个)

  1. READ UNCOMMITTED(读未提交数据)

    隔离级别最低,安全性最差,但是性能最高,不能防止一切问题(可能会出现脏读、不可重复读和幻读)

  2. REAN COMMITTED(读已提交数据)(Oracle默认)

    隔离级别较低,安全性较差,性能略高(安全性比第一个级别高,但是性能比第一个级别差)

    可以防止脏读,但是还是可能会出现不可重复读和幻读

  3. REPEATABLE READ(可重复读)(MySQL默认)

    隔离级别较高,安全性高,性能略差(安全性比上一级高,但是性能比上一级别差)

    可以防止脏读和不可重复读,但是不能防止幻读

  4. SERIALIZABLE(串行化)

    不会出现任何并发问题,因为它对同一数据的访问是串行的,非并发访问,隔离级别最高,安全性最高,但性能最差!

设置隔离级别

Mysql查询当前的事务隔离级别

select @@tx_isolation;

mysql设置事务隔离级别:

  1. set tx_isolation=‘read-uncommitted’;

    安全性最差,容易出现脏读、不可重复读、幻读,但性能最高

  2. set tx_isolation=‘read-committed’;

    安全性一般,可防止脏读,但容易出现不可重复读、幻读

  3. set tx_isolation=‘repeatable-read’;

    安全性较好,可防止脏读、不可重复读,但是容易出现幻读

  4. set tx_isolation=‘serialiable’;

    安全性最好,可以防止一切事务并发问题,但是性能最差

JDBC设置事务隔离级别

JDBC中通过Connection提供的方法设置事务隔离级别:

Connection.setTransactionIsolation(int level)

参数可选值如下:

参数类型数字表示
Connection.TRANSACTION_READ_UNCOMMITTED1读未提交数据
Connection.TRANSACTION_READ_COMMITTED2读已提交数据
Connection.TRANSACTION_REPEATABLE_READ4可重复读
Connection.TRANSACTION_SERIALIZABLE8串行化
Cnnection.TRANSACTION_NONE0不使用事务

提示:在开发中,一般情况下不需要修改事务隔离级别,只有查询不需要设置隔离级别

JDBC中实现事务:

package com.wep.c3p0;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.wep.util.JDBCUtil;
/**
 * 测试JDBC事务
 */
public class TestTransaction {
	static Connection conn;
	static Statement stat;
	static ResultSet rs;
	//创建一个连接池(对象)
	static ComboPooledDataSource pool = new ComboPooledDataSource();
	public static void main(String[] args) {
		 try {	 
			//从连接池中获取连接对象
			conn = pool.getConnection();		
			//设置取消自动提交事务(改为手动提交)
			conn.setAutoCommit(false);	
			 //3.获取传输器
			stat = conn.createStatement();	
			//转账:A转给B 100元
			String sql1 = "update acc set money = money - 100 where name = 'A'";
			String sql2 = "update acc set money = money + 100 where name = 'B'" ;		
			stat.executeUpdate(sql1);
			stat.executeUpdate(sql2);		
			//提交事务
			conn.commit();
			System.out.println("执行成功,提交事务!");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("执行出错,回滚事务!");
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			JDBCUtil.close(conn, stat, rs);
		}
	}
}

网页编程基础-HTML

盖房子:砖块搭建房子+涂料/石灰/油漆

做网页:html标签组织网页的结构+css渲染/美化网页

html内容:

  1. 如何写一个简单符合规范的网页
  2. 如何处理网页中的中文乱码问题
  3. 如何在网页中插入一副图像和创建一个超链接
  4. 如何在网页中插入一个表格
  5. 如何在网页中插入一个表单

HTML概述

什么是HTML?

HTML:Hyber Text Markup Language 超文本标记语言

做网页的最基础的开发语言 W3C组织

关于HTML:

  1. html开发网页文件以.html或者htm为后缀
  2. html是通过标签来组织网页结构的
  3. html开发的网页由浏览器负责解析并显示
  4. html就是文档的一种(txt、word、ppt、excel、html等)

乱码产生的本质:编码时和解码时使用的码表不一致造成的!

关于网页乱码问题

关于乱码的解决:只要保证网页文件保存时的编码(可以通过文件另存为…来确认)和meta标签指定的编码相同,就可以保证网页没有乱码问题

案例1:编写我的第一个网页

<!DOCTYPE HTML>
<html>
	<head>
		<title>first page</title>
        <meta charset="utf-8"/>
	</head>
	<body>
		<h1>Hello 2021</h1>
	</body>
</html>

<!DOCTYPE HTML> – 文档声明,用于声明当前文档是一个html网页文档,并且版本是html5.0

<html> – 根标签,按照规范,所有的网页内容都应该包含在根标签内部

<head> – 头部分,用于存放网页的基本属性信息(比如网页的标题,比如网页使用的编码,比如引入CSS文件等)

<body> – 体部分,用于存放真正可视化的网页内容(即放在body中的内容通常可以显示在网页中)

HTML语法

  1. html标签

    标签也叫做标记、元素、节点,是用<>括起来的一组内容

    标签还分为开始标签(<head>)和结束标签(</head>),开始标签和结束标签之间可以包含其他内容(比如标签内还可以包含标签或文本)

    另外,有些标签内部没有内容,可以写成自闭标签,例如:<meta/> == <meta></meta>、<input/>、<img/>、<br/>、<hr/>等

  2. html属性

    属性不能独立存在,必须声明在开始标签上,属性可以有多个,多个属性之间用空格分隔,属性的值可以使用单引号或者双引号引起来:

    <meta charset=“utf-8” id=“m1”/>

  3. 注释,格式:<-- 注释内容 -->,快捷键 ctrl+shift+/

    注意:注释不能嵌套注释

    <h1>你好 2021</h1>
    <!--<h1>你好 2021</h1>-->
    
  4. html空格和换行

    在浏览器中,多个连续的空白字符(可能是空格/制表符/换行)会显示为一个空格,因此:

    ​ 如果要在网页中做一个换行:<br/>

    ​ 如果要在网页中做一个空格:&nbsp; (中文空格:&emsp;)

关于路径的写法:

不要再开发中书写带盘符的路径(例如:d:\xx\xx),因为将来项目发布的系统可能是没有盘符的,因此写带盘符的路径非常不靠谱。

推荐些相对路径,即相对于一个文件的位置去找另一个文件。例如:

在 D:\Setup\Java\code\02-图像和超链接.html 文件中引入一副图像。其中图片的路径是相对于当前网页的路径:imgs/1.jpg

浏览器只要知道html文件的路径,就可以找到图片的位置

html文件的路径为:

D:\Setup\Java\code\02-图像和超链接.html

因此图片的位置为:

D:\Setup\Java\code\imgs\1.jpg

图像标签

图像标签用于在网页中插入一副图像

<img src=“1.jpg” border=“5px” width=“500px”/>

其中src用于执行图片的路径

width用于指定图片的宽度,height用于指定高度

超链接

		<h3>创建一个超链接</h3>
		<a href="http://www.baidu.com" target="blank">
			百度一下,你就知道
			</a>
		<br/>
		<a href="imgs/wht.jpg" width="500px">王海涛</a>

其中href属性用于点击超链接后指定所跳转到的地址,target属性用于执行点击超链接后以何种方式打开超链接

表格标签

表格标签是一组标签,其中包括table、tr、td、th等

table – 用于定义一个表格

tr – 用于定义表格中的行

td/th – 用于定义表格行中单元格

例如:

<table>
	<tr>
        <td>xxx</td>
		...
    </tr>
    ...
</table>

示例:插入一个4行4列的表格

<!doctype html>
<html>
	<head>
		<title>third page</title>
		<meta charset="utf-8"/>
		<style>
			table{
				border:1px solid red;
				/* 设置表格边框合并 */
				border-collapse:collapse;
				/* 设置表格宽度 */
				width:70%;
				/* 让左右外边距自适应,使表格居中 */
				margin-left:auto;
				margin-right:auto;
				/* 为表格设置背景颜色 */
				background: pink;
			}
			td,th{
				border:1px solid red;
				/* 设置表格边框合并 */
				border-collapse:collapse;
				/* 设置元素边框和内容之间的距离 */
				padding:10px;
			}
			h1{
				/* border:1px solid green; */
				text-align:center;
			}
		</style>
	</head>
	<body>
		<h1>插入一个4行4列的表格</h1>
		<table>
			
			<tr>
				<th>表头1</th>
				<th>表头2</th>
				<th>表头3</th>
				<th>表头4</th>
			</tr>

			<tr>
				<td>21</td>
				<td>22</td>
				<td>23</td>
				<td>24</td>
			</tr>
			
			<tr>
				<td>31</td>
				<td>32</td>
				<td>33</td>
				<td>34</td>
			</tr>

			<tr>
				<td>41</td>
				<td>42</td>
				<td>43</td>
				<td>44</td>
			</tr>
			
		</table>
		
	</body>
</html>

表单

通过form标签可以在网页中定义一个表单

表单的作用:用于向服务器提交数据

向服务器提交/发送数据的方式一共两种:

  1. 通过表单可以向服务器发送数据

    在表单中,可以输入数据,通过提交/注册可以将表单中的数据提交给服务器,服务器再接收这些数据进行处理!

  2. 通过超链接可以向服务器发送数据

    http://www.tmooc.cn/?username=zhangfei&pwd=123&like=football

    在URL的后面,可以通过问号拼接参数,当访问url所在的服务器时,会将问号后面的参数一并带给服务器。服务器再接收这些数据进行处理!

表单标签

<form>标签用于再网页中定义一个表单

<form action="" method="">

​ //可以有很多个表单项标签,比如用户名输入框、密码输入框。

<form>

action属性用于指定将表单及表单中的数据提交到哪一个位置(服务器)

method属性用于指定表单的提交方式,常用的方式有GET提交和POST提交(http协议中介绍GET和POST)

表单项标签

注意:

  • 所有需要提交数据给服务器的表单项都需要指定name属性,如果不指定,在提交表单时,该项将会被忽略,不予提交!

  • 如果是单选框或复选框,不仅需要指定name属性,还需要指定value属性,value就是提交的值,如不指定,默认值是on

  1. input 标签

    • 普通文本输入框

      <input type="text" name="username"/>
      
    • 密码输入框

      <input type="password" name="password"/>
      
    • 单选框

      <input type="radio" name="gender" value="man/woman" checked="checked"/>
      <!-- checked="checked" 设置默认选中 -->
      
    • 复选框

      <input type="checkbox" name="like"/>
      
    • 按钮

      <input type="button value="换一张"/>
      
    • 提交按钮

      <input type="submit"/>
      
  2. select / option 标签

    实现下拉选框

    <select name="city">
        <option vlaue="bj" selected="selected">北京</option>
    </select>
    <!-- 假如选中北京选项,提交时,提交值是bj,如不指定value值,将会提交option标签的内容,也就是北京 -->
    <!-- selected="selected"设置为默认值 -->
    
  3. textarea 标签

    实现多行输入框

    <textarea cols="30" rows="5"></textarea>
    <!-- cols用于指定列数,也就是宽度 -->
    <!-- rows用于指定行数,也就是高度 -->
    <!-- placeholder用于指定提示内容 -->
    

案例:

<!DOCTYPE HTML>
<html>
	<head>
		<title>form</title>
		<meta charset="utf-8"/>
		<style>
			table{
				/*设置边框合并*/
				border-collapse:collapse;
				/*设置表格居中*/
				margin-left:auto;
				margin-right:auto;
				/*设置背景颜色*/
				background:white;
			}
			td{
				/*设置边框和颜色*/
				border:2px solid lightgrey;
				/*设置内容和边框之间的距离*/
				padding:10px;
			}
			h1{
				text-align:center;
			}
			#last-td{/*选中id为last-td的元素*/
				/*设置元素内容居中*/
				text-align:center;
			}
		</style>
	</head>
	<body>
		<h1>欢迎注册</h1>
		<form action="#" method="GET">
			<table>
				<tr>
					<td>用户名:</td>
					<td>
						<input type="text" name="username">
					</td>

				</tr>
				
				<tr>
					<td>密码:</td>
					<td>
						<input type="password" name="password"/>
					</td>
				</tr>
				<tr>
					<td>性别:</td>
					<td>
						<input type="radio" name="gender" value="man"/><input type="radio" name="gender" value="woman"/></td>
				</tr>
				<tr>
					<td>爱好:</td>
					<td>
						<input type="checkbox" name="like" value="basketball"/>篮球
						<input type="checkbox" name="like" value="football"/>足球
						<input type="checkbox" name="like" value="volleyball"/>排球
					</td>

				</tr>
				<tr>
					<td>城市:</td>
					<td>
					<select name="city">
						</option>
						<option value="bj">北京</option>
						<option value="sh">上海</option>
						<option vlaue="gz">广州</option>
						<option value="sz">深圳</option>
					</select>
					</td>
				</tr>
				<tr>
					<td>验证码:</td>
					<td>
					<input type="text" name="verifycode"/>
					<img src="../imgs/vc.jpg">
					<input type="button" value="换一个"/>
					</td>
				</tr>
				<tr>
					<td>自我描述:</td>
					<td>
					<textarea name="description" type="text" cols="30" rows="5" placeholder="请输入描述信息..." style="resize:none"></textarea>
					</td>
				</tr>
				<tr>
					<td colspan="2" id="last-td">
					<input type="submit" value="注册"/>
					</td>
				</tr>				
			</table>
		</form>
	</body>
</html>

CSS基础

什么是CSS

CSS:层叠样式表,其实就是用于美化/渲染网页的一门技术

使用css美化网页,可以使得将展示数据的html代码和设置样式的css代码进行分离,可以增强网页的展示能力

在HTML中引入CSS

  1. 通过标签的style属性引入css

  2. 通过head标签内部的style标签引入css

    <style type="text/css">
    /* ****** CSS样式 ****** */
    span{
    border:2px solid green;
    font-size:30px;
    font-weight:bolder;
    }
    </style>
    

    这种方式是将css属性写在一个style标签内部,没有写在某一个元素上,这样不会造成页面结构的混乱,也实现了代码的复用,推荐使用!

  3. 通过link标签引入内部的css文件

    在head标签内:

    <!-- 引入css文件 -->>
    <link rel="stylesheet" href="demo.css"/>
    

    在demo.css文件中:

    p{
    	border:2px solid blue;
        color:red;
        font-family:"华文琥珀";
        text-indent:50px;
    }
    

    需要注意:css文件另存时的编码要指定为utf-8

    这种方式是将所有的css代码通过一个css文件进行管理,真正实现了将html代码和css代码进行分离,也实现了代码的复用

CSS选择器

选择器:能够帮助我们选中元素进行修饰。

基本选择器

  1. 元素名/标签名选择器

    格式:元素名称或标签名称{ 若干css属性… }

    通过元素的名称选中当前网页中所有指定名称的元素,进行样式设置

    示例:

    /* 1.标签名选择器 */
    span{
    background:#DDA0DD;
    font-size:24px;
    font-weight:bolder;
    	}
    
  2. class/类选择器

    格式:.class的值{ 若干css属性… }

    通过标签上的class属性可以为每一个元素设置所属的组/类,通过class值,可以选中所有的class值相同的元素,统一设置样式

    示例:

    .c1{
    background:#CBF74B;
    color:green;
    	}
    /* (2)将div1下的span和内容为"span111"的span字体颜色设置blue, 背景颜色设置为#F0E68C ,c2属性覆盖c1 */
    .c2{
    color:blue;
    background:#F0E68C;
    	}
    

    另外一个元素也可以设置多个class值,中间用空格分隔。

    <span class="c1 c2">
    span11
    </span>
    

    这样表示span既属于c1,也属于c2,c1和c2都会同时作用到这个span上,如果设置了同样的样式但是值不同,后设置的会覆盖前面设置的。

  3. id选择器

    格式:#id的值{ 若干css属性… }

    通过元素上通用的属性id可以为元素设置一个独一无二的编号,通过该编号可以唯一地找到一个元素。因此可以通过id的值获取唯一一个元素

    示例:

    /* 3.id选择器 */
    /*用id选择器将第一个p标签设置字体大小为28px,字体颜色为yellow,首行文本缩进20px*/
    #p1{
    font-size:28px;
    color:yellow;
    text-indent:20px;
    	}
    

拓展选择器

  1. 后代选择器(指定标签下所有的子标签)

    格式:父选择器 后代元素选择器{ css属性… }

    在选中的父类元素的内部,匹配所有指定的后代元素

    /* ------1.后代选择器------ */
    /*将div下所有的span标签的字体大小设置为22px, 背景颜色设置为#DDA0DD*/
    /*span{} 表明选中当前文档中所有的span元素*/
    #d1 span{
    	font-size:24px;
    	background:#DDA0DD;
    }
    
  2. 子元素选择器(指定标签下所有的一级标签)

    格式:父选择器>子元素选择器{ css属性… }

    在选中的父元素的内部,匹配所有指定的子元素

    /* ------2.子元素选择器------ */
    /*将div下所有的span子元素标签的字体大小设置为16px, 背景颜色设置为#DEB887*/
    #d1>span{
    	font-size:18px;
    	background:#DEB887;
    }
    
  3. 属性选择器(指定标签和标签属性),多个属性用多个[]来区分

    格式:选择器[属性条件…][属性条件…]…{ css属性… }

    根据元素及元素的属性条件来匹配元素

    /* ------3.属性选择器------ */
    /*为所有的文本输入框,设置背景颜色为pink,字体大小为30px,首行缩进30px*/
    input[type='text'][name="username"]{
    	background:pink;
    	font-size:30px;
    	text-indent:30px;
    }
    
  4. 伪类选择器。

    格式:选择器:状态{ css属性… }

    根据元素的所属状态选中元素

    a:hover{/*当鼠标悬停在a元素上时,才具有如下样式*/
    color:green;
    font-size:28px;
    border:2px solid red;
    text-decoration:none;
    	}
    /*(2)给div下的第一个a元素设置背景颜色为 yellow.*/
    div a:first-child{
    background:yellow;
    	}
    

常用属性总结

  1. 文本相关属性

    text-align:设置文本水平排列方式

    ​ left 居左,right 居右,center 居中

    text-indent:设置文本首行缩进,单位是像素/百分比

    text-decoration:设置文本的下划线样式,常见取值:

    ​ underline:有下划线

    ​ none:无下划线

    text-shadow:设置文本阴影,取值:值1,值2,值3,值4;

    ​ 值1:设置阴影水平偏移位置

    ​ 值2:设置阴影垂直偏移位置

    ​ 值3:设置阴影模糊程度

    ​ 值4:设置阴影颜色

  2. 字体相关属性

    font-size:字体大小

    font-weight:字体粗细,取值:normal bold bolder

    font-family:设置字体,“宋体”,“黑体”等

    color:设置字体颜色

    line-height:设置行高

  3. 背景相关属性

    background-color:设置背景颜色

    background-image:设置背景图片

    background-position:设置背景图片的位置

    background-repeat:设置背景图片是否以及如何排列

  4. 其他属性

    width:宽度

    height:高度

实现永和后台管理页面

<!doctype html>
<html>
	<head>
		<title>first page</title>
		<meta charset="utf-8"/>
	</head>
		<!--frameset:框架集,框架在这里指窗口-->
		<frameset rows="10%,90%" frameborder="0">
			<frame src="_top.html"/>
			<frameset cols="180px,*"><!--*号表示剩余-->
				<frame src="_left.html"/>
				<frame src="_right.html"/>
				</frameset>
		</frameset>
	<body>
	</body>
</html>

<!-- top -->
<!doctype html>
<html>
	<head>
		<title>first page</title>
		<meta charset="utf-8"/>
		
		<style>
			body{
				background:steelblue;
			}
			h1{
				color:#fff;
				text-indent:20px;
				letter-spacing:5px;
				text-shadow:5px 5px 5px #000;
			}
		</style>
	</head>
	<body>
			<h1>永和大王门店管理系统</h1>
		
	</body>
</html>

<!-- left -->
<!doctype html>
<html>
	<head>
		<title>first page</title>
		<meta charset="utf-8"/>
		<style>
			body{
				background:#1F2A31;
				/*样式重置(css reset)*/
				margin:0px;
			}
			div{
				height:40px;
				border-bottom:1px solid darkgray;
				/*border-bottom:1px solid #fff;*/
				font-size:16px;
				/*在div垂直方向居中*/
				line-height:40px;
				text-align:center;
				letter-spacing:4px;
			}
			div a{
				/*设置颜色为白色*/
				color:#fff;
				/*设置无下划线*/
				text-decoration:none;
			}
			/*div:last-child{
				border-bottom:1px solid darkgray;
			}*/
			/*当鼠标悬停在div上时,出现如下样式*/
			div:hover{
				background:dimgray;
			}
			}

		</style>
	</head>
	<body>
		<div>
			<a href="#">› 门店管理</a>
		</div>
		<div>
			<a href="#">› 订单管理</a>
		</div>
	</body>
</html>

<!-- right -->
<!doctype html>
<html>
	<head>
		<title>first page</title>
		<meta charset="utf-8"/>
		<style>
			body{
				background:#FFFEFF;
			}
			#wel{
				text-align:center;
				font-size:36px;
				/*margin-top:180px;*/
				padding-top:180px;
				color:#686868;
				text-shadow:1px 1px 1px #000;
			}
		</style>
	</head>
	<body>
		<div id="wel">
			欢迎访问永和大王门店管理系统...
		</div>
	</body>
</html>

JavaScript

JavaScript简介

什么是JavaScript?

全程是JavaScript,简称JS

JS是嵌入在网页中执行的一段小程序,由浏览器负责解析并执行

常被用于嵌入在网页中实现动画效果或者实现表单校验

JS特点和优势

  • JS的特点

    • JS是一门直译式的语言

      不需要编译

      直接写在html中或者写在JS文件中由html引用

    • JS是一门基于对象的语言

      JS严格来说不能算是面向对象的语言

      但是可以通过一些机制来模拟面向对象

      可以说JS是基于对象的

    • JS是一门弱类型语言,变量可以指向任何数据类型

      String str = “java”;

      var str = “JS”;//字符串

      str = 100;//数值

      str = true;//布尔类型

      str = [];//数组

  • JS的优势

    • 交互式

    • 安全性

      不能访问电脑硬盘

    • 跨平台性

在HTML书写JS的方式

  1. 在head或页面中的其他位置,在一个<script>标签内部可以直接书写JS代码

    <!doctype html>
    <html>
    	<head>
    		<title>first page</title>
    		<meta charset="utf-8"/>
    		<script>
    			//JS中提供的实现弹框的方法			
    			alert("Hello JS");
    			alert(3+6);
    		</script>
    	</head>
    	<body>
    
    	</body>
    </html>
    
  2. 在html中,引入外部JS文件

    <!--第二种方式:引入外部的JS文件-->
    <script src="demo.js"></script>
    

    需要注意的是:在第二种方式中,script标签内部不要些JS代码,如果写了JS代码,也不会执行!!

关于JS的注释,和Java的注释格式一样:

//单行注释

/* 多行注释 */

数据类型

  • 基本数据类型

    • 数值类型(number)

      在JS底层,数值类型只有一种,就是浮点型

      但是有时浮点型和整型会自动进行类型转换

      如:3.4+2.6=6;//不是6.0

      NaN 非数字

      Infinity

      -Infinity

    • 字符串类型

      在JS中,字符串属于基本数据类型,而且字符串可以使用单引号或者双引号引起来

      var str1 = “hello”;

      var str2 = ‘hello’;

    • 布尔类型

      布尔类型的值只有true和false

    • undefined

      如果声明了变量,但是没有为变量赋值,该变量的值是undefined

      var x;

      alert(x);//undefined

    • null

      null类型的值也只有一个,就是null

      null表示空值,可以作为函数的返回值,表示函数返回的是一个空的对象

  • 复杂数据类型

    数组、函数、对象都是复杂数据类型,是对象

变量和运算符

变量的定义

JS中声明变量全都是通过var关键字

通过var关键字声明的变量不区分类型,可以指向任意的数据

var x = 100;

x = true;

x = “hello”;

x = [];

x = function(){}…

数组:

java:String[] s = {};

JS:var arr = [];//声明一个长度为0的空数组

var arr = [“hello”,100,true,new Object()];//声明一个具有指定初始值的数组

​ var arr = new Array();//声明一个长度为0的空数组

JS中的数组可以存放任意的数据类型,可以理解为java中的Object数组

通过length属性获取数组的长度

JS中的数组长度可以随时发生变化

函数:

格式一:

function 函数名(参数){

​ 代码块(函数体)

}

格式二:

var 函数名/变量名 = function(参数){

​ 代码块(函数体)

}

JS中的运算符

JS中的运算符跟Java大致相同

JS中的语句跟Java大致相同

DOM操作

DOM:Document Object Moder 文档对象模型,为JS操作html文档所提供的一套API,通过这套API可以很方便地对html元素进行增删改查操作,比如:

获取一个HTML元素

删除一个html元素

对某一个html元素进行修改

创建一个html元素

将创建的html添加到另一个元素的内部

获取元素

document.getElementById(id值) – 通过id获取一个指定id的元素,返回的是一个JS对象,表示获取的这个元素

ele.parentNode – 获取当前元素的父元素

parent.removeChild(child) – 通过父元素删除子元素

JS增删改元素

document.createElement(元素名) – 创建指定名称的元素,返回的是一个JS对象,表示创建的新的元素

obj.innerHTML – 设置或获取指定元素的所有内容

document.body – 获取当前html文档中的body元素

parent.appendChild(child) – 通过父元素添加一个子元素,或者将子元素添加到父元素内部

其他方法

new Date() – 创建一个代表当前日期的JS对象

date.toLocaleString() – 根据本地时间格式,将日期对象转为一个时间字符串

<!doctype html>
<html>
	<head>
		<title>元素的增删改查</title>
        <!--或者写成:<meta charset="utf-8"/> -->
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
		<style type="text/css">
			div { border:#0099FF 2px solid;height:
			60px;width:300px;margin:20px 10px;
			padding:10px;line-height:60px;font-size:26px;text-align:center;
			}
			#div_1{background-color:#00FFFF;}
			#div_2{background-color:#FF3399;}
			#div_3{background-color:#00FF00;}
			#div_4{background-color:#FFFF66;}
			#info{wifth:250px;height:90px;font-size:22px;padding:5px;resize:none;}
			input{font-size:18px;}
		</style>
		<script type="text/javascript">
			// 1. 当鼠标点进输入框时,清除提示消息
			function focusTA(thisobj){
				//鼠标点进输入框时,如果内容等于“请输入描述信息...”,则清空内容
				if(thisobj.value == "请输入描述信息..."){
					thisobj.value="";
				}
			}

			//2.当鼠标离开输入框时,恢复提示信息
			function blurTA(thisobj){
				//鼠标离开输入框时,如果内容等于空,则恢复提示消息
				if(thisobj.value == ""){
					thisobj.value="请输入描述信息...";
				}
			}

			//3.添加元素:添加一个div元素到body中
			function addNode(){
                    docment.getElementById("11").click();
                    //1.创建一个新的div元素
                    var divObj = document.createElement("div");
                    //为创建的div设置内容
                    divObj.innerHTML = "我是新来的~";
                    //2.获取body元素
                    var body = document.body;
                    //3.将div元素添加到body内部
                    body.appendChild(divObj);
                }

			//4.删除元素:删除id为div_2的元素
			function deleteNode(){
				//1.获取要删除的元素
				var div2 = document.getElementById("div_2");
				//2.获取要删除元素的父元素
				var body = div2.parentNode;
				//3.通过父元素删除子元素
				body.removeChild(div2);
			} 

			//5.更新元素内容:将div_3的内容更新为当前时间
			function updateNode(){
				//1.获取id为div_3的元素
				var div3 = document.getElementById("div_3");
				//2.将div_3的内容更新为当前时间
				var date = new Date().toLocaleString();
				div3.innerHTML = date;
			}

			</script>
	</head>
	<body>
		<h3>鼠标点进输入框、鼠标离开输入框</h3>
		<textarea id="info" onfocus="focusTA(this)" onblur="blurTA(this)">请输入描述信息...</textarea><br/><br/>

		<input type="button" id="11" onclick="addNode()"
			value="创建一个div添加到body中"/>
		<input type="button" onclick="deleteNode()" value="删除id为div_2的元素"/>
		<input type="button" onclick="updateNode()" value="将div_3的内容更新为当前时间"/><hr/>
		<div id="div_1">
			div_1
		</div>
		<div id="div_2">
			div_2
		</div>
		<div id="div_3">
			div_3
		</div>

	</body>
</html>

JQuery简介

什么是JQuery

JQuery是一个轻量的、免费开源的JS函数库,可以极大地简化JS代码

轻量:所谓的轻量,是指对一个技术的依赖程度越低,耦合性越低,这个技术就越轻;反过来,如果对一个技术或框架的依赖程度越高,耦合性越高,这个技术就越重。

JQuery的优势

  • 可以简化JS代码

  • 可以向CSS选择器一样非常方便地获取元素

  • 可以通过修改CSS属性控制页面的效果

    举例:修改所有class值为c1的元素的样式

    $(".c1").css({

    ​ “border” : “2px solid red”,

    ​ “width” : “200px”,

    ​ “background” : “pink”

    })

  • 可以兼容常用的浏览器

    JS中removeNode()、replaceNode()、innerText在有些浏览器中是不兼容的。

    但是JQuery也提供了对应的函数,都是兼容常用浏览器的

    常用浏览器(火狐/谷歌chrome/欧朋/苹果…)

JQuery引入

由于JQuery的库文件就是一个普通的JS文件,所以和引入普通的JS文件方式一样,示例:

<head>
	<meta charset="utf-8"/>
	<!--引入JQuery-->
	<script src="js/jquery-1.8.3.min.js"></script>
</head>

如果引入后,按F12浏览器的控制台中,没有报错误,说明引入成功

如果引入后,浏览器的控制台上,报了如下错误:net:ERR_FILE_NOT_FOUND,则说明JQuery引入失败,通常是文件路径书写错误导致!

文档就绪事件

文档就绪事件函数:在浏览器加载完当前html文档之后立即执行的函数,就是文档就绪事件函数

JQuery提供的文档就绪事件函数:

$(function(){

​ //整个html文档加载完之后立即执行…

});

另外,JS也提供了文档就绪事件函数:

window.onload = function(){

​ //整个html文档加载完之后立即执行…

}

JQuery选择器

基本选择器

<style>
	#d1{xxx}
\</style>

\<script>
	$("#d1")
	$("#div span")
\<script/>
  1. 元素名(标签名)选择器

    $(“div”) – 匹配所有的div元素

    $(“span”) – 匹配所有的span元素

  2. 类选择器

    $(“div.mini”) – 匹配所有class为mini的div元素

  3. ID选择器

    $("#one") – 匹配id为one的元素

层级选择器

  1. 后代选择器

    $(“div span”) – 匹配div内部的所有span后代元素

  2. 子元素选择器

    $(“div>span”) – 匹配div内部的所有span子元素

  3. 相邻兄弟选择器

    $("#one+span") – 匹配id为one的元素下一个紧邻的span兄弟元素

    $("#one").next(“span”) --匹配id为one的元素下一个紧邻的span元素

    $("#one").prev(“span”) – 匹配id为one的元素前一个紧邻的span元素

    $(“one”).nextAll(“span”) – 匹配id为one的元素后面所有的span兄弟元素

    $("#one").prevAll(“span”) – 匹配id为one的元素后面所有的span兄弟元素

    $("#one").siblings(“span”) – 匹配id为one的元素前后所有的span兄弟元素

    $("#one~span") – 匹配id为one的元素后面所有的span兄弟元素

基本过滤选择器

  1. :first | :last

    $(“span:first”)

    $(“span:eq(0)”)

    $(“span”).eq(0) --匹配所有span中的第一个span元素

    $(“span:last”) – 匹配所有span中的最后一个span元素

    ( " s p a n " ) . e q ( ("span").eq( ("span").eq((“span”).length-1) – 匹配所有span中的最后一个span元素

  2. :eq(n)

    $(“div:eq(n)”)

    $(“div”).eq(n) – 匹配所有div中的第n+1个div元素

为元素绑定事件的方式有很多种,以点击事件为例:

为id为b1的按钮绑定点击事件,点击b1后执行一个弹框

方式一:通过在标签上添加onclick属性为元素绑定点击事件

<script>
	function fn(){
		alert("b1按钮被点击了")
    }
</script>
<input type="button" id="b1" value="b1,改变所有div元素的背景色为#FA8072" onclick="fn()"/>

方式二:通过JS对象调用onclick属性,为元素绑定点击事件

<script>
var b1 = document.getElementById("b1");
b1.onclick = function(){
	alert("b1按钮被点击了")
}
</script>
<input type="button" id="b1" value="b1,改变所有div元素的背景色为#FA8072" onclick="fn()"/>

方式三:通过JQuery的click函数为元素绑定点击事件

<script>
	$("#b1").click(function(){
        alert("b1按钮被点击了")
    });
</script>
<input type="button" id="b1" value="b1,改变所有div元素的背景色为#FA8072" onclick="fn()"/>

案例一:(引入jquery)

<!doctype html>
<html>
<head>
	<meta charset="utf-8"/>
	<!--引入JQuery-->
	<script src="js/jquery-1.8.3.min.js"></script>
	<script>
		/*在浏览器加载完整个html文档之后立即执行*/
		$(function(){
			/*获取h1标签中的内容(innerHTML)*/
			var h1 = document.getElementById("d1");
			alert(h1.innerHTML);
		});
		/*window.onload = function(){} js提供的文档就绪事件,等同于Jquery中的$(function(){})*/
		
	</script>
</head>
<body>
	<h1 id="d1">Hello JQuery</h1>

</body>
</html>

案例二:

<!DOCTYPE>
<html>
<head>
<title>基本选择器练习</title>
<meta charset="utf-8"/>
<style type="text/css">
	body{ font-family: "微软雅黑" }
	div,span { width: 140px;height: 140px;margin: 20px;background: #9999CC;border: #000 1px solid;float: left;font-size: 17px;font-family: Roman;}
	div.mini{width:60px;height:50px;background:#CC66FF;border:#000 1px solid;font-size:12px;font-family:Roman;}
	div.mini01{height:50px;width:65px;background:pink;}
	input{margin:5px 5px;}
</style>

<!-- 引入jquery函数库文件 -->
<script src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
	/* 文档就绪事件函数(即在浏览器加载完最后一个标签后立即执行) */
	$(function() {
		/* ---------基本选择器练习--------- */
		/* 1、选中b1按钮,为b1按钮绑定点击事件,点击b1按钮:
			改变元素名为 div 的所有元素的背景色为 #FA8072  */
			$("#b1").click(function(){
				$("div").css("background","#FA8072");
			});
		
		/* 2、选中b2按钮,为b2按钮绑定点击事件,点击b2按钮:
			改变 id 为 one 的元素的背景色为 #9ACD32  */
			$("#b2").click(function(){
				$("#one").css("background","#9ACD32")
			});

		/* 3、选中b3按钮,为b3按钮绑定点击事件,点击b3按钮:
			改变 class 为 mini 的所有元素的背景色为 #EE82EE  */
			$("#b3").click(function(){
				$(".mini").css("background","#EE82EE")
			});
		});
</script>
</head>

<body>
	<!-- 按钮1 -->
	<input type="button" value=" 改变元素名为 div 的所有元素的背景色为 #FA8072 " id="b1"/>
	<!-- 按钮2 -->
	<input type="button" value=" 改变 id 为 one 的元素的背景色为 #9ACD32 " id="b2" />
	<!-- 按钮3 -->
	<input type="button" value=" 改变 class 为 mini 的所有元素的背景色为 #EE82EE " id="b3" />

	<h1>点击按钮查看效果...</h1>

	<div id="one">div: id为one</div>

	<div id="two" class="mini">
		div: id为two,class是 mini
		<div class="mini"> class是 mini</div>
	</div>

	<div class="one">
		div: class是 one
		<div class="mini"> div: class是 mini</div>
		<div class="mini"> div: class是 mini</div>
	</div>
	
	<div class="one">
		div: class是 one
		<div class="mini01"> div: class是 mini01</div>
		<div class="mini"> div: class是 mini</div>
	</div>
	
	<div>div</div>

	<span> span </span>
	<span class="mini"> span: class是mini </span>
</body>
</html>

案例三:

<!DOCTYPE HTML>
<html>
<head>
<title>层级选择器</title>
<meta charset="utf-8"/>
<style type="text/css">
	div,span{font-size:14px;width:140px;height:140px;margin:20px;background:#9999CC;border:#000 1px solid;float:left;font-size:17px;font-family:Roman;}
	.mini,div.mini01{width:80px;height:70px;background:#CC66FF;border:#000 1px solid;font-family:Roman;}
	div.mini01{height:65px;width:65px;background-color:pink;}
	input{margin:5px 5px;}
</style>

<!--引入jquery的js库-->
<script src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
	/* 文档就绪事件函数(即在浏览器加载完最后一个标签后立即执行) */
	$(function() {
		/* ---------层级选择器练习--------- */
		/* 1、选中b1按钮,为b1按钮绑定点击事件,点击b1按钮:
			改变 div 内所有 span 的背景色为 #FF0000  */
		$("#b1").click(function(){
			$("div span").css("background","#FF0000");
		});
		
		/* 2、选中b2按钮,为b2按钮绑定点击事件,点击b2按钮:
			改变 body 内子 div 的背景色为 #FFFF00  */
		$("#b2").click(function(){
			$("body>div").css("background","#FFFF00")
		});
		
		/* 3、选中b3按钮,为b3按钮绑定点击事件,点击b3按钮:
			改变 id 为 two 的下一个 div 的背景色为 #0000FF  */
		$("#b3").click(function(){
			//$("#two+div").css("background","#0000FF");
			$("#two").next().css("background","#0000FF");
			//$("#two").prev().css("background","#0000FF");前一个
		});


		/* 4、选中b4按钮,为b4按钮绑定点击事件
			改变 id 为 two 的元素后面的所有 div 兄弟元素的背景色为 #76AA0F  */
		$("#b4").click(function(){
			$("#two").nextAll("div").css("background","#76AA0F");
			//$("#two").prevAll("div").css("background","#76AA0F");
		})
		
		/* 5、选中b5按钮,为b5按钮绑定点击事件
			改变 id 为 two 的元素所有 div 兄弟元素的背景色为 #FF69B4  */
		$("#b5").click(function(){
			$("#two").siblings("div").css("background","#FF69B4");
		});
		/*基本过滤选择器*/
		/*6.选中b6按钮,为b6按钮绑定点击事件,点击b9按钮实现:改变第一个/最后一个div元素的背景色为#1E90FF*/
		$("#b6").click(function(){
			$("div:first").css("background","#1E90FF");
			$("div:last").css("background","#1E90FF");
		});
		/*7.选中b7按钮,为b7按钮绑定点击事件,点击b7按钮实现:改变第4个div元素的背景色为#EA3AD8*/
		$("#b7").click(function(){
			$("div:eq(3)").css("background","#EA3AD8");
		});
	});
</script>
</head>

<body>
	<input type="button" value=" 改变 div 内所有 span 的背景色为 #FF0000 " id="b1" />
	<input type="button" value=" 改变 body 内子 div 的背景色为 #FFFF00 " id="b2" />
	<input type="button" value=" 改变 id 为 two 的下一个 div 的背景色为 #0000FF " id="b3" />
	<input type="button" value=" 改变 id 为 two 的元素后面的所有 div 兄弟元素的背景色为 #76AA0F " id="b4" />
	<input type="button" value=" 改变 id 为 two 的元素所有  div 兄弟元素的背景色为 ##FF69B4 " id="b5" />
	<input type="button" value=" 改变 第一个/最后一个 div元素 的背景色为 #1E90FF " id="b6" />
	<input type="button" value=" 改变 第4个 div元素 的背景色为 #EA3AD8 " id="b7" />

	<h1>点击按钮查看效果...</h1>

	<div id="one">div:id为one</div>
	<div class="one">
		div:class为one
		<span class="mini"> span</span>
		<div class="mini"> div</div>
	</div>
	<div id="two">
		div:id为two
		<div class="mini"> div</div>
	</div>
	<div>
		div:
		<div class="mini01"> div</div>
		<span class="mini"> span</span>
	</div>
	<div class="one"> div</div>	<br>
	<span class="one"> span</span>	<br>
</body>
</html>

JQuery创建表格元素

  • $("<table><table>") – 创建一个table元素,返回的是一个JQuery,用于表示创建的table元素

  • $("<table><tr><td>我是单元格</td><tr></table>")

    创建一个包含内容的table元素,返回的是一个JQuery,用于表示创建的table元素

  • p a r e n t . a p p e n d ( parent.append( parent.append(child) – 父元素添加子元素

  • $(“div”).remove(); – 删除所有匹配的div元素

  • $(“div”).replaceWith("<p>我是来替换的</p>"); – 将所有匹配的div元素替换为p元素

  • $(“td”).html(); – 获取td元素的内容,如果td有多个,此处只返回第一个td的内容

  • $(“td”).html(“我是td”) – 为所有匹配的td元素设置内容,如果td中有内容,会产生覆盖

  • $(“input”).val() – 获取所匹配的input元素的值或者输入框中的内容,如果input有多个,也只是获取第一个input元素的value值

  • $(“input”).val(“值”) – 为所有匹配的input元素的值或者输入框中设置内容

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>创建表格</title>

<style type="text/css">
	/* 为表格定义CSS样式 */
	body{padding-left:15px;font-size:20px;}
	table{ border:1px solid #0099FF; width:70%; border-collapse:collapse; }
	table td{ border:#0099FF 1px solid; padding:10px 20px 3px 1px; }
	input[type='text']{width:150px;height:20px;vertical-align:text-bottom;text-indent:5px;font-size:20px;}
	input[type='button']{font-size:20px;}
</style>

<!-- 引入jquery函数库文件 -->
<script src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
	//创建单行单列的表格

	function createTable1(){
		//1.创建一个table元素		
		var $tab = $("<table></table");
		//2.创建一个tr元素
		var $tr = $("<tr></tr>");
		//3.创建一个td元素
		var $td = $("<td>我是单元格</td>");
		//$td.html("我是单元格");可以在td中添加,也可以使用td的html方法添加内容
		//4.将td添加到tr中
		$tr.append($td);
		//5.将tr添加到table中
		$tab.append($tr);
		//6.将table添加到body中
		$("body").append($tab);

	//$("body").append("<table><tr><td>hello</td></tr></table>");上述代码可以用该行实现
	}


	//创建5行6列的表格
	function createTable2(){
		//1.创建一个table元素		
		var $tab = $("<table></table");
		for(var i = 0;i < 5;i++){
			//2.创建一个tr元素
			var $tr = $("<tr></tr>");
			for(var j = 0;j < 6;j++){
				//3.创建一个td元素
				var $td = $("<td>我是单元格</td>");
				//$td.html("我是单元格");可以在td中添加,也可以使用td的html方法添加内容
				//4.将td添加到tr中
				$tr.append($td);
			}
				//5.将tr添加到table中
				$tab.append($tr);

		}
			//6.将table添加到body中
			$("body").append($tab);

	}

	//创建指定行和列的表格
	function createTable3(){
		//0.获取用户输入的行数和列数
		var rows = $("#rows").val();
		var cols = $("#cols").val();
		//1.创建一个table元素		
		var $tab = $("<table></table");
		for(var i = 0;i < rows;i++){
			//2.创建一个tr元素
			var $tr = $("<tr></tr>");
			for(var j = 0;j < cols;j++){
				//3.创建一个td元素
				var $td = $("<td>我是单元格</td>");
				//$td.html("我是单元格");可以在td中添加,也可以使用td的html方法添加内容
				//4.将td添加到tr中
				$tr.append($td);
			}
				//5.将tr添加到table中
				$tab.append($tr);

		}
			//6.将table添加到body中
			$("body").append($tab);
	}
</script>
</head>
<body>
	<!-- 点击下列按钮创建单行单列表格 -->
	<input type="button" value="创建单行单列表格" onclick="createTable1()" /><br/><br/>

	<!-- 点击下列按钮创建5行6列表格 -->
	<input type="button" value="创建表格(5行6列)" onclick="createTable2()" /><br/><br/>

	<!-- 点击下列按钮创建指定行、指定列的表格 -->
	<input type="button" value="创建表格(输入行数和列数)" onclick="createTable3()" /><br/>
	行数:<input type="text" id="rows"/><br/>
	列数:<input type="text" id="cols"/><br/><br/>
	<!-- 将创建的表格添加到body内部(追加到最后) --><hr/>
</body>
</html>

QQ好友分组案例:

  • css中display属性:可以设置元素显示或隐藏

    取值为none表示隐藏,取值为biock表示显示

  • $show() – 设置元素为显示,等价于css(“display”,“block”)

    $hide() – 设置元素为隐藏,等价于css(“display”,“none”)

  • $toggle() – 切换元素的显示状态

    如果元素本身是隐藏的,toggle之后,元素会变为显示状态

    如果元素本身是显示的,toggle之后,元素会变为隐藏状态

  • $parent() – 获取当前匹配元素的父元素

    $obj.parent() – 获取当前匹配元素的祖先元素

    $obj.find() – 获取当前匹配元素的所有后代元素

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>仿QQ好友分组</title>
<style type="text/css">
	table{border:#09f 1px solid;width:100px;border-collapse:collapse;margin:15px 10px;width:10%;margin:20px 20px;}
	table td{border:#06f 1px solid;background-color:#6f5f3e;text-align:center;padding:5px 0;}
	table td div{background-color:#ff9;text-align:left;line-height:28px;padding-left:14px;text-indent:padding-left:20px;}
	table td span{color:#fff;font-size:19px;width:100%;border:none;display:block;cursor:pointer;}
	table td a:hover{color:#0c0}
</style>
<!--引入jquery的js库-->
<script src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
	/* -- 通过jQuery实现仿QQ列表好友列表 -- */
	function openDiv(thisobj){
		//关闭其他三个分组内的div
		$(thisobj).parents("tr").siblings("tr").find("div").hide();
		
		//通过传过来的span元素找到相邻的div元素,将div设置为显示或隐藏,如果div是隐藏的,则设置为显示,反之设置为隐藏
		$(thisobj).next("div").toggle();
	}
	
	/* -- 通过javascipt实现仿QQ列表好友列表 --
	function openDiv(thisobj){
		//1.获取当前分组内好友列表div
		var oDiv = thisobj.parentNode.getElementsByTagName("div")[0];
		//2.判断当前分组div是展开还是关闭
		if(oDiv.style.display == "block"){
			//3.如果当前div是打开的, 只需关闭该div即可
			oDiv.style.display = "none";
		}else{
			//4.如果当前div是关闭的, 先关闭其他分组的div, 再打开当前的  
			//获取所有分组内的div,遍历依次关闭所有分组
			var aDiv = document.getElementsByTagName("div");
			for(var i=0;i<aDiv.length; i++){
				aDiv[i].style.display = "none";
			}
			//再打开当前分组
			oDiv.style.display = "block";
		}
	} */
</script>
</head>
<body>
<table>
	<tr>
		<td>
			<span onclick="openDiv(this)">君王好友</span>
			<div style="display:none">
				秦始皇<br />
				刘邦<br />
				李世民<br />
				康熙<br />
			</div>
		</td>
	</tr>
	<tr>
		<td>
			<span onclick="openDiv(this)">三国好友</span>
			<div style="display:none">
				刘备<br />
				关羽<br />
				张飞<br />
				赵云<br />
			</div>
		</td>
	</tr>
	<tr>
		<td>
			<span onclick="openDiv(this)">美女好友</span>
			<div style="display:none">
				西施<br />
				貂蝉<br />
				杨贵妃<br />
				王昭君<br />
			</div>
		</td>
	</tr>
	<tr>
		<td>
			<span onclick="openDiv(this)">IT好友</span>
			<div style="display:none">
				王海涛<br />
				马云<br />
				李开复<br />
				俞敏洪<br />
			</div>
		</td>
	</tr>
</table>
</body>
</html>

全选全不选案例:

prop() --property(属性),可以获取或设置元素的属性值(JQuery1.6版本及之后使用)

attr() – 可以获取或设置元素的属性值(JQuery1.6版本之前使用)

$(“input[type=‘checkbox’].prop(“checked”)”) – 获取匹配的复选框的checked属性值

$(“input[type=‘checkbox’].prop(“checked”),true”) – 设置所有匹配的复选框的checked属性值为true(即设置复选框选中)

<!DOCTYPE HTML>
<html>
<head>
<title>table练习</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
	body{font-family: "微软雅黑"}
	h2,h4{text-align: center;}
	div#box1, div#box2 {text-align:center;}
	table{margin: 0 auto;width: 70%;text-align: center;border-collapse:collapse;}
	td, th{padding: 7px; width:20%;}
	th{background-color: #DCDCDC;}
</style>

<!--引入jquery的js库-->
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
	/* 点击全选设置 员工所在的行全选或者全不选 */
	//1.获取全选复选框,绑定点击事件
	$(function(){
		$("#all").click(function(){
			//2.获取全选复选框的选中状态(全选复选框的checked属性值)
			var status = $("#all").prop("checked");
			//3.将全选复选框的选中状态设置其他复选框
			$("input[type='checkbox']:not(#all)").prop("checked",status);
		});
	});
</script>
</head>

<body>
	<h2>员工列表</h2>
	<table border="1">
		<tr>
			<th>
				<input type="checkbox" id="all"/>
				<!--全选-->
			</th>
			<th>ID</th>
			<th>姓名</th>
			<th>邮箱</th>
			<th>工资</th>
		</tr>
		<tr>
			<td>
				<input type="checkbox"/>
			</td>
			<td>1</td>
			<td>宋江</td>
			<td>sj@163.com</td>
			<td>12000</td>
		</tr>
		<tr>
			<td>
				<input type="checkbox"/>
			</td>
			<td>2</td>
			<td>武松</td>
			<td>ws@163.com</td>
			<td>10500</td>
		</tr>
		<tr>
			<td>
				<input type="checkbox"/>
			</td>
			<td>3</td>
			<td>孙二娘</td>
			<td>sen@163.com</td>
			<td>11000</td>
		</tr>
	</table>
</body>
</html>

TOMCAT

服务器的概述

什么是服务器

服务器分为服务器软件和服务器硬件

服务器硬件:通常是一台配置很高的计算机

服务器软件:是运行在服务器上的程序(软件),服务器软件分为很多种类:邮件服务器、ftp服务器、数据库服务器、web服务器

什么是Web服务器

web服务器是运行在互联网上的计算机程序,专门接收客户端浏览器的请求,并根据请求做出响应

启动服务器后,服务器会监听一个8080端口,可以通过浏览器访问:http://localhost:8080 http://127.0.0.1:8080 http://192.168.1.103:8080(局域网ip)

如果无法访问网站,可能是服务器未能成功启动,或者是访问的主机名或端口有误

修改默认端口

如果不修改默认端口(8080),每次访问tomcat都需要在主机名后面加上:8080;如果想在访问时,省略不写端口,可以将8080改为80端口,由于80端口比较特殊,可以省略不写

修改方式:到tomcat安装目录下:/conf/server.xml,在69行找到Connector标签上的port属性,将值改为80即可

服务器无法启动

安装目录下查看logs操作日志,如果显示服务器被占用,则可能有以下两种情况:

  • 可能是上次启动的tomcat服务器没有完全关闭,导致再次启动失败

    解决方案:使用shutdown.bat将服务器按照正常的关闭流程再关闭一次,再次启动服务器,如果启动成功,则说明问题已经解决,否则看第二种情况:

  • 可能是别的程序再占用80端口

    解决方法:找到占用80端口的进程,将进程结束即可

    通过再cmd中输入命令:netstat -ano 查看当前系统中所有活动的进程及所占用的端口,再通过taskkill /f /pid 进程编号 将进程结束即可,结束后再次启动服务器即可

tomcat目录结构

  • bin:存放批处理文件的目录

  • conf:存放配置文件的目录(比如server.xml是tomcat服务器的核心配置文件)

  • lib:tomcat运行时所依赖的jar包的存放目录

  • logs:tomcat运行时产生的日志文件会保存在该目录下

  • temp:tomcat存放临时文件的目录

  • webapps:localhost虚拟主机默认管理的目录,将开发的web应用程序放在webapps目录下,就可以通过localhost主机进行访问

    简单理解:就是将一些资源放在webapps目录下,通过浏览器就可以访问

  • work:tomcat存放工作文件的目录(jsp翻译后的Servlet文件)

虚拟主机和Web应用

虚拟主机

虚拟主机是指tomcat服务器中配置的一个站点(网站)

在tomcat服务器中可以配置多个站点,每一个站点都是一台虚拟主机,比如tomcat服务器中默认提供了一个虚拟主机,就是localhost

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

那么其中name属性用于指定主机名,appBase指定主机默认管理的目录

Web应用

Web应用就是一个目录,其中可以存放很多资源文件(比如html/css/js/图片/Servlet/jsp等…),将这些资源文件按照一定的规则进行存放,组织成的目录就是一个Web应用

image-20210317193300359

tomcat服务器中可以配置多台虚拟主机,每一台虚拟主机中可以发布多个web应用,每一个web应用都是一个目录,其中存放了很多资源文件

Web应用的目录结构

news(Web应用的目录)

  • 其他目录:放在其他目录中的资源文件,通过浏览器可以直接访问
  • WEB-INF目录:放在WEB-INF中的文件,通过浏览器不能直接访问
    • classes:存放编译后的class文件
    • lib:存放web应用所依赖的jar报
    • web.xml:和当前web应用相关的配置文件

部署Web应用到虚拟机

将Web应用的目录直接拷贝到虚拟主机默认管理的目录下即可

比如将news目录直接拷贝到localhost虚拟主机默认管理的目录下–webapps目录下即可

配置缺省的(默认的)WEB应用

在没有将news这个应用配置为缺省的web应用前,访问hello.html的路径为:http://localhost/news/hello.html

将news这个应用配置为缺省的web应用后,访问hello.html的路径为:http://localhost/hello.html

如何将news配置为缺省的(默认的)web应用:将news目录名改为一个大写的ROOT即可

配置WEB应用的主页

将hello.html配置为主页之前,访问hello.html的路径为:

http://localhost/hello.html

将hello.html配置为主页之后,访问hello.html的路径为:http://localhost

如何将hello.html配置为主页

到当前的web应用下的web.xml文件中,在根标签内部,添加如下内容:

<welcome-file-list>
    <welcome-file>hello.html</welcome-file>>
</welcome-file-list>

打war包

war包、zip包、rar包、jar包本质上都是一种压缩包

将web应用打成一个压缩包,格式就是war包,这样的好处:

  • 文件体积会更小,传输更快
  • 将war包发布到服务器中,war可以自动解压发布

需要注意:

  • 打成的war包的名字不能和已发布的目录名重复,否则不会自动解压
  • war包中不能包含中文的文件名和目录名,否则也不会自动解压发布

HTTP协议

概述

什么是HTTP协议

Http协议:用于规定浏览器和服务器之间的通信方式

主要用于规定浏览器给服务器发送请求信息时,需要遵循什么格式(即请求信息的格式)

同时也规定了服务器给浏览器做响应时,需要遵循什么格式

http工作时遵循的基本原则:

  • 一次请求,只能对应一次响应
  • 请求只能由浏览器发送给服务器,服务器只能被动等待请求,做出回应

协议详解

http请求
GET /news/hello.html?username=zhangfei&password=123 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive

请求行

GET /news/hello.html?username=zhangfei&password=123 HTTP/1.1

GET:请求方式,在Http协议中一共规定了7种提交方式,常用的只有GET/POST

/news/hello.html:请求资源路径,表示浏览器请求的是哪一个web应用,以及web应用下的哪一个资源文件

HTTP/1.1:请求所遵循的协议和版本

若干请求头

xxx:xxx
xxx:xxx
...

Host:localhost:8080 :表示浏览器请求的是哪一台主机

xxx:xxx

请求实体内容

请求头和请求实体内容之间由空白行

如果请求方式是GET提交,那么请求实体一定是空的,如果请求方式是POST提交,并且请求中携带了数据,请求实体才会有内容

http响应
HTTP/1.1 200 OK
Server:Apache-Coyote/1.1
Accept-Ranges:bytes
ETag:W/"73-1562745162000"
Last-Modified:Wed,10 Jul 2019 07:52:42 GMT
Content-Type:text/html
Content-Length:73
Date:Thu,11 Jul 2019 01:21:27 GMT

<meta charset="utf-8"/>
<h1>hello 你好</h1>

状态行

HTTP/1.1 200 OK

HTTP/1.1:响应所遵循的协议和版本

200:状态码,三位的数字(100~600),表示服务器对请求处理的结果

​ 200:表示请求处理成功

​ 404:表示浏览器请求的资源不存在

​ 500:表示服务器在处理请求的过程中出现了异常

若干响应头

Server:Apache-Coyote/1.1
Accept-Ranges:bytes
ETag:W/"73-1562745162000"
Last-Modified:Wed,10 Jul 2019 07:52:42 GMT
Content-Type:text/html
Content-Length:73
Date:Thu,11 Jul 2019 01:21:27 GMT

Refresh : 3;url=http://www.baidu.com

Set-Cookie:xx

(空白行)

响应实体内容

<meta charset="utf-8"/>
<h1>hello 你好</h1>

浏览器所请求文件的内容,会通过响应实体发送给浏览器

比如:浏览器请求localhost主机内部news应用下的hello.html这个文件,服务器就会将hello.html文件的内容,通过响应实体发送给浏览器

GET提交和POST提交的区别

区别主要体现在请求参数传输过程的不同

  • GET提交的参数是通过请求行提交给服务器的,会在地址栏中体进行显示,非常不安全

    POST提交的参数是通过实体提交给服务器的,不会显示在地址栏中,相对更加安全

  • GET提交提交的参数是通过请求行提交给服务器的,会在地址栏中进行显示,数据量不能太大,一般不能超过1kb或4kb

    POST提交通过请求实体提交参数,数据量理论上是没有限制的

Servlet核心

Servlet概述

什么是Servlet?

Servlet是sun公司提供的一门动态web资源开发技术(实际上是一组规范或接口)

Servlet本质上就是一个Java程序,和普通的Java程序不同的是,Servlet程度无法独立运行(里面没有main函数),必须放在服务器中,由服务器调用才可以执行

service(request,response),参数对象通常由服务器创建

Servlet的作用?

image-20210319000705097

  • 浏览器向服务器发送请求,服务器调用一个Servlet来处理
  • Servlet负责对请求进行处理,处理的过程中可能需要连接并访问数据库,最终得出一个结果
  • 通常Servlet不直接将结果响应给浏览器,而是由JSP或者html负责展示
  • 最终要响应的结果由服务器负责响应给浏览器

开发Servlet程序

开发Servlet程序的步骤

  1. 写一个类,实现一个Servlet接口并实现其中的方法
  2. 在web应用的web.xml文件中配置Servlet对外访问的路径

使用eclipse创建web项目

  1. 创建一个web工程:在左侧窗口中,鼠标右键–new–Dynamic Web Project

  2. 接着会弹出窗口:

    项目名 Hello

    Target runtime:Apache Tomcat v8.0(选择对应版本)

    Dynamic web module version:2.5(默认是3.1,3.1版本不会创建web.xml文件,并且创建Servlet时不会在web.xml文件中生成servlet相关配置信息)

使用eclipse创建servlet

  1. 选中项目中的src目录,鼠标右键–new–Servlet

  2. 在弹出的窗口中:

    Java package:com.wep

    Class name:HelloServlet

    Superclass:javax.servlet.http.HttpServlet(默认),继承了Servlet类

    finish

通过eclipse创建servlet,默认继承HttpServlet。由于HttpServlet也是Servlet接口的子类,让HelloServlet继承HttpServlet,相当于间接实现了Servlet接口

继承HttpServlet类,默认会覆盖doGet方法和doPost方法,两个方法的作用为:

doGet方法:当浏览器发送请求的方式为GET提交时,服务器将会调用doGet方法来处理请求

doPost方法:当浏览器发送请求的方式为POST提交时,服务器将会调用doPost方法来处理请求

Servlet在web.xml中的配置

在通过eclipse创建Servlet时,会自动在web.xml文件中进行Servlet相关信息的配置

(注意:如果是复制类文件,配置信息不会配置,需要手动配置)

  <servlet>
    <description></description>
    <display-name>HelloServlet</display-name>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.wep.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/HelloServlet</url-pattern>
  </servlet-mapping>

关于上面的配置信息:

  • eclipse每创建一个Servlet,就会在web.xml文件中添加两个标签:

    <servlet>和<servlet-mapping>标签(可以将这两个标签看成一个组的标签)

  • <servlet>和<servlet-mapping>标签内都会有一个<servlet-name>标签,标签的内容可以更改,但要求更改后的这两个<servlet-name>标签的内容必须一致

  • <servlet-class>标签用于配置Servlet类的全路径名(即包名+类名)

    需要注意:如果在创建servlet后修改了servelt类的名称,这个地方也要一起更改,否则将会出现“ClassNotFoundException”即类找不到异常

  • <url-pattern>标签用于配置浏览器以什么路径访问当前servlet(即servlet对外访问的路径)默认的路径是:/类名

例如:上面为HelloServlet配置的<url-pattern>为/HelloServlet,因此我们在浏览器中的访问路径为:

http://主机名/web项目访问路径/HelloServlet

运行Servlet程序、访问测试

  1. 在运行servlet上点击右键–Run As–“1 Run on Server”

  2. 在弹出的窗口中,直接点击完成即可

  3. 运行结果出来后,复制系统浏览器的路径,到常用浏览器中粘贴访问

  4. 在运行的同时,web应用也会被发布(部署)到tomcat服务器中,如下:

    运行的同时,web应用也会被发布到tomcat服务器中,如下:servers–服务器–项目

    image-20210320144832759

思考:

  • eclipse部署web应用到tomcat,那么部署的位置在哪里?如何修改这个位置

    eclipse默认会将web应用发布到这个目录下:

    workspace\.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps

    如果要修改发布的路径,可以双击服务器,在弹出的窗口中找到如下图所示的位置,但是发现不能修改选项

    image-20210320155710861

    可以将服务器中所有已发布的web应用从服务器移除,再在服务器上右键点击clean…,此时,回到上面的窗口,就可以修改其中的配置了:

    image-20210320160144100

  • 通过eclipse部署到web应用到tomcat服务器,是如何实现部署的?或者eclipse是如何将web应用发布到服务器中的?

image-20210320183648869

Servlet继承关系

  • servlet接口–定义一个servlet程序应该具备哪些功能

    • –GenericServlet抽象类,实现了Servlet接口,并且实现了其中大部分的方法,但是没有实现service方法,因为service是处理的核心方法,这个方法应该由开发人员自己来实现

      • HttpServlet抽象类,继承了GenericServlet类,也继承了其中的方法,同时还实现了父类没有实现的service方法,在service方法中,根据不同的请求方式调用不同的doXxx方法。例如请求方法是GET提交,将会调用doGet方法,如果请求时POST提交,将会调用doPost方法

        因此,以后在开发Servlet时,可以写一个类,直接继承HttpServlet,并覆盖其中的doGet和doPost方法,分别来处理GET和POST请求即可(非必须)

image-20210320190818686

servlet调用过程

image-20210320231043494

request和response

request是代表http请求信息的对象,其中封装了浏览器发送过来的请求信息

response是代表http响应信息的对象,其中封装了将要发送给浏览器的响应信息

在服务器接收浏览器的请求之后,在调用service方法处理请求之前,服务器会创建request和response对象,分别用来封装请求和响应信息

request

获取请求参数

请求参数:

da哪个浏览器访问服务器时,发送给服务器的数据就是请求参数

比如:在登录时或者注册时,浏览器需要将用户名和密码等信息发送给服务器,这些发送给服务器的用户名和密码就是请求参数

image-20210321223749003

如何获取请求参数?

request.getParameter(String name);

– 通过请求参数的名字,获取对应的参数值

request.getParameterValues();

– 通过请求参数的名字,获取对应的所有参数值组成的数组,返回的是一个字符串数组

如何处理请求参数的乱码问题?

  • 如果是GET提交,并且tomcat是8.0及以后的版本,GET提交的中文参数是没有乱码的,因为tomcat服务器底层针对GET提交的参数乱码已经做了处理

  • 但是如果是tomcat7.0及7.0之前的版本,GET提交的中文参数也是有乱码的。如何处理?

    在tomcat服务器/conf/server.xml中修改端口的Connector标签上添加一个属性:

    image-20210322210840728

  • 如果时POST提交,不管是哪个版本的tomcat服务器,POST提交的中文参数都是有乱码的,处理方式是,在任何获取参数的代码之前,添加一行设置:

    //针对POST提交的参数乱码问题
    request.setCharacterEncoding("utf-8");
    
    //获取参数
    String user = request.getParameter("username");
    System.out.println(user);
    

请求转发、作为域对象

请求转发:资源跳转的一种方式,这种跳转对外是不可见的(浏览器看不见)。当浏览器发请求访问服务器中的一个资源(比如Servlet),而这个Servlet最终没有做出响应,而是将请求转交给另外一个资源(比如Servlet/JSP等),由另外的这个资源来做响应,那么将请求从一个资源转交给另外一个资源的过程就是请求转发。

image-20210322231849110

实现转发代码:

request.getRequestDispatcher("所转发到资源的路径").forward(req,res)

作为域对象使用:如果一个对象具备可以被访问的范围,利用该对象上的map集合,可以在整个范围内实现资源的共享

request就是一个域对象,在一次请求范围内request对象都是同一个,并且request对象上保存了一个map集合,专门用于存取数据

package com.wep.req;
/**模拟查询个人信息*/
import java.io.IOException;
import java.io.PrintWriter;

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

public class RequestDemo2 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");
		PrintWriter out = response.getWriter();
		//模拟通过JDBC访问数据库查询个人信息
		String name = "小明";
		String addr = "广东广州";
		//将数据存入到request对象的map集合中
		request.setAttribute("name", name);
		request.setAttribute("addr", addr);
		//通过转发将request对象带到jsp,取出数据进行显示
		request.getRequestDispatcher("index.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
}


<%@ page pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
	p{border:2px solid red;background:pink;}
</style>
</head>
<body>
	<h1>index.jsp...</h1>
	<p><%=request.getAttribute("name")%></p>
	<p><%=request.getAttribute("name")%></p>
	
</body>
</html>

运行结果:

image-20210323233119285

请求转发的特征:

  • 转发前后是一次请求,一次响应
  • 转发前后浏览器的地址没有发生变化
  • 转发只能是同一个web应用内部的两个资源进行(A转发给B,A和B必须是同一个web应用)
  • 转发前后的request对象是同一个,因为转发前后是同一个请求,而服务器针对一次请求只会创建一个request对象,因此在转发前后可以通过request带数据到目的地

request提供的存取数据的方法:

request.setAttribute(String name,Object value);

– 往request域中添加一个域属性,属性名必须是字符串,属性值可以是任意类型

request.getAttribute(String name);

– 根据属性的名称获取对应的属性值

response对象

表示Http响应的对象,用于封装将要发送给浏览器的响应信息

向客户端发送数据

PrintWriter out = response.getWriter();

out.write(“hello”);

image-20210324223011672

通过response.getWriter获取的流,向浏览器发送数据时,默认使用的编码是iso8859-1,而这个码表中没有中文字符,所以在发送中文数据时,如果使用默认的编码(iso8859-1),一定会出现乱码问题!

解决方法:response.setContentType(“text/html;charset=utf-8”);

  • 通知服务器使用utf-8发数据给浏览器
  • 通知浏览器也是用utf-8接收服务器发过来的数据
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值