数据库的概述
什么是数据库
数据库:简而言之,就是存储数据,管理数据的仓库。
根据数据库底层结构的不同,数据库可以分为很多种类:
- 层次式数据库
- 网络式数据库
- 关系型数据库(市场主流)
- 非关系型数据库
关系型数据库
以二维表的形式保存数据的数据库就是关系型数据库,例如:
Student | name | age | score |
---|---|---|---|
1 | 张三 | 18 | 98 |
2 | 李四 | 17 | 87 |
3 | 王五 | 19 | 85 |
提示:非关系型数据库底层是键值对结构(如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
Mysql | Java |
---|---|
tinyint | byte |
smallint | short |
int | int |
double | double |
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不可以
例:
stuid | name | age | score | createtime | timestamp |
---|---|---|---|---|---|
1 | 张三 | 18 | 98 | 手动插入 | 自动插入 |
2 | 李四 | 17 | 87 | 手动插入 | 自动插入 |
3 | 王五 | 19 | 85 | 手动插入 | 自动插入 |
上表中,如果时间格式为createtime格式,则不会自动更新时间,需要手动插入;而如果为timestamp格式,则会自动更新为当前时间
新增、修改、删除表记录
通过cmd插入或查询数据的编码问题:
-
插入数据乱码问题,解决方案:
-
确认所插入的数据库的编码,在建库时是否指定为utf8,查看建库时的语句:show create database 库名
如果建库时,没有指定编码,默认编码是latin1,而latin1没有中文,所以在存储中文数据时,必然会出现乱码问题,因此需要将库删除重建,重建时,指定编码为utf8,例如:create database 库名 charset utf8;或者直接修改数据库的编码为utf8:alter database 库名 charset utf8;
-
如果上面的确认库的编码是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():求平均值
外键
所谓的外键,就是用于通知数据库中两张表列和列之间的对应关系,并且可以让数据库帮我们维护这段关系的列就叫做外键
用来保存数据库中两张表的对应关系,可以在一张表中指定另一张表的主键为外键(当然也可以不指定)。指定了外键,数据库知道两张表之间的关系并帮我们维护,若不指定,需要人为维护。
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;
数据乱码问题
设置默认编码
修改C:\Program Files\MariaDB 10.5\data 目录下的my.ini
重启服务器命令:
停止服务器: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
jdbc连接访问数据库:
-
注册数据库驱动(将mysql驱动包交给jdbc来管理,方便我们使用驱动包中的API)
Class.forName("com.mysql.jdbc.Driver");
之前我们通过DriverManager.registerDriver( new Driver() );这种方法注册驱动,但这种方法有两个不好的地方:
- 会导致驱动注册两次
- 会让程序和具体的驱动包绑死在一起(无法导入java.sql包,只能导入com.mysql.jdbc包)。Class.forName(“com.mysql.jdbc.Driver”)中的字符串后期可以提取到配置文件中,不需要重新编译,因此用这种方式注册驱动不会将程序和驱动绑死
-
获取数据库连接( 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返回数据)
-
获取传输器
Statement stat = conn.createStatement();
-
利用传输器发送sql到服务器执行,并返回执行结果
-
使用传输器的executeQuery(sql)方法来查询结果(返回的是查询结果)
-
使用传输器的executeUpdate(sql)方法来更新值(返回的是作用的行数)
String sql = "select * from account";//account;后面的分号可不加 ResultSet rs = stat.executeQuery(sql); stat.executeUpdate(sql);
-
-
处理结果
遍历传输器返回的值
while(rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); double money = rs.getDouble("money"); System.out.println(id+":"+name+":"+money); }
-
释放资源
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)
什么是连接池
常量池、线程池、连接池
池:是指内存中的一片空间,可以理解为是一个容器
连接池:就是将一批连接存放在一个容器中,供整个程序共享。这样可以减少连接创建和关闭的次数,提高程序的效率,实现连接的复用
传统方式每次需要连接就创建连接,用完连接后就关闭连接,而创建连接和关闭连接需要消耗大量的时间和资源,会导致程序效率低下
如何提高程序执行的效率,减少连接创建和关闭的次数,实现连接的复用?
使用连接池操作数据库:
在程序一启动时,就初始化一批连接放在一个池子中,供整个程序共享。当用户访问数据库需要连接时,不要自己创建,而是从连接池中获取一个连接进行使用,当用完连接也不要将连接关闭,而是将连接还回池中,这样一来,既减少了连接创建和关闭的次数,也实现了连接的复用,提高了程序的效率。
为什么要使用连接池
- 不使用连接池:每次需要连接都创建连接,用完之后就直接关闭,连接没有复用,而且创建和关闭连接需要消耗大量的时间和资源,所以会造成程序效率低下
- 使用连接池:每次需要连接不用再创建,而是直接从连接池中获取一个连接对象,用完后将连接直接还回连接池中。这样一来减少了连接创建和关闭的次数,实现了连接的复用,提高了程序执行的效率!
如何使用C3P0连接池
使用C3P0开发步骤:
-
导入开发包
-
创建数据库连接池
//创建连接池对象 ComboPooledDataSource pool = new ComboPooledDataSource();
-
设置连接数据库的基本信息
-
方式一:(不推荐)
//注册驱动 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语句绑定在一起执行,要么全都执行成功,要么全都执行失败!(有一个失败就算失败)
到网上买东西:下订单到支付,对数据库中数据的影响:
- 在订单中会多一个订单记录
- 同时会修改商品的库存数量
再比如,转账: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的记录(感觉像是出现了幻觉)。这种情况称之为"幻读"
事务的隔离级别(四个)
-
READ UNCOMMITTED(读未提交数据)
隔离级别最低,安全性最差,但是性能最高,不能防止一切问题(可能会出现脏读、不可重复读和幻读)
-
REAN COMMITTED(读已提交数据)(Oracle默认)
隔离级别较低,安全性较差,性能略高(安全性比第一个级别高,但是性能比第一个级别差)
可以防止脏读,但是还是可能会出现不可重复读和幻读
-
REPEATABLE READ(可重复读)(MySQL默认)
隔离级别较高,安全性高,性能略差(安全性比上一级高,但是性能比上一级别差)
可以防止脏读和不可重复读,但是不能防止幻读
-
SERIALIZABLE(串行化)
不会出现任何并发问题,因为它对同一数据的访问是串行的,非并发访问,隔离级别最高,安全性最高,但性能最差!
设置隔离级别
Mysql查询当前的事务隔离级别
select @@tx_isolation;
mysql设置事务隔离级别:
-
set tx_isolation=‘read-uncommitted’;
安全性最差,容易出现脏读、不可重复读、幻读,但性能最高
-
set tx_isolation=‘read-committed’;
安全性一般,可防止脏读,但容易出现不可重复读、幻读
-
set tx_isolation=‘repeatable-read’;
安全性较好,可防止脏读、不可重复读,但是容易出现幻读
-
set tx_isolation=‘serialiable’;
安全性最好,可以防止一切事务并发问题,但是性能最差
JDBC设置事务隔离级别
JDBC中通过Connection提供的方法设置事务隔离级别:
Connection.setTransactionIsolation(int level)
参数可选值如下:
参数类型 | 数字 | 表示 |
---|---|---|
Connection.TRANSACTION_READ_UNCOMMITTED | 1 | 读未提交数据 |
Connection.TRANSACTION_READ_COMMITTED | 2 | 读已提交数据 |
Connection.TRANSACTION_REPEATABLE_READ | 4 | 可重复读 |
Connection.TRANSACTION_SERIALIZABLE | 8 | 串行化 |
Cnnection.TRANSACTION_NONE | 0 | 不使用事务 |
提示:在开发中,一般情况下不需要修改事务隔离级别,只有查询不需要设置隔离级别
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内容:
- 如何写一个简单符合规范的网页
- 如何处理网页中的中文乱码问题
- 如何在网页中插入一副图像和创建一个超链接
- 如何在网页中插入一个表格
- 如何在网页中插入一个表单
HTML概述
什么是HTML?
HTML:Hyber Text Markup Language 超文本标记语言
做网页的最基础的开发语言 W3C组织
关于HTML:
- html开发网页文件以.html或者htm为后缀
- html是通过标签来组织网页结构的
- html开发的网页由浏览器负责解析并显示
- 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语法
-
html标签
标签也叫做标记、元素、节点,是用<>括起来的一组内容
标签还分为开始标签(<head>)和结束标签(</head>),开始标签和结束标签之间可以包含其他内容(比如标签内还可以包含标签或文本)
另外,有些标签内部没有内容,可以写成自闭标签,例如:<meta/> == <meta></meta>、<input/>、<img/>、<br/>、<hr/>等
-
html属性
属性不能独立存在,必须声明在开始标签上,属性可以有多个,多个属性之间用空格分隔,属性的值可以使用单引号或者双引号引起来:
<meta charset=“utf-8” id=“m1”/>
-
注释,格式:<-- 注释内容 -->,快捷键 ctrl+shift+/
注意:注释不能嵌套注释
<h1>你好 2021</h1> <!--<h1>你好 2021</h1>-->
-
html空格和换行
在浏览器中,多个连续的空白字符(可能是空格/制表符/换行)会显示为一个空格,因此:
如果要在网页中做一个换行:<br/>
如果要在网页中做一个空格: (中文空格: )
关于路径的写法:
不要再开发中书写带盘符的路径(例如: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标签可以在网页中定义一个表单
表单的作用:用于向服务器提交数据
向服务器提交/发送数据的方式一共两种:
-
通过表单可以向服务器发送数据
在表单中,可以输入数据,通过提交/注册可以将表单中的数据提交给服务器,服务器再接收这些数据进行处理!
-
通过超链接可以向服务器发送数据
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
-
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"/>
-
-
select / option 标签
实现下拉选框
<select name="city"> <option vlaue="bj" selected="selected">北京</option> </select> <!-- 假如选中北京选项,提交时,提交值是bj,如不指定value值,将会提交option标签的内容,也就是北京 --> <!-- selected="selected"设置为默认值 -->
-
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
-
通过标签的style属性引入css
-
通过head标签内部的style标签引入css
<style type="text/css"> /* ****** CSS样式 ****** */ span{ border:2px solid green; font-size:30px; font-weight:bolder; } </style>
这种方式是将css属性写在一个style标签内部,没有写在某一个元素上,这样不会造成页面结构的混乱,也实现了代码的复用,推荐使用!
-
通过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选择器
选择器:能够帮助我们选中元素进行修饰。
基本选择器
-
元素名/标签名选择器
格式:元素名称或标签名称{ 若干css属性… }
通过元素的名称选中当前网页中所有指定名称的元素,进行样式设置
示例:
/* 1.标签名选择器 */ span{ background:#DDA0DD; font-size:24px; font-weight:bolder; }
-
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上,如果设置了同样的样式但是值不同,后设置的会覆盖前面设置的。
-
id选择器
格式:#id的值{ 若干css属性… }
通过元素上通用的属性id可以为元素设置一个独一无二的编号,通过该编号可以唯一地找到一个元素。因此可以通过id的值获取唯一一个元素
示例:
/* 3.id选择器 */ /*用id选择器将第一个p标签设置字体大小为28px,字体颜色为yellow,首行文本缩进20px*/ #p1{ font-size:28px; color:yellow; text-indent:20px; }
拓展选择器
-
后代选择器(指定标签下所有的子标签)
格式:父选择器 后代元素选择器{ css属性… }
在选中的父类元素的内部,匹配所有指定的后代元素
/* ------1.后代选择器------ */ /*将div下所有的span标签的字体大小设置为22px, 背景颜色设置为#DDA0DD*/ /*span{} 表明选中当前文档中所有的span元素*/ #d1 span{ font-size:24px; background:#DDA0DD; }
-
子元素选择器(指定标签下所有的一级标签)
格式:父选择器>子元素选择器{ css属性… }
在选中的父元素的内部,匹配所有指定的子元素
/* ------2.子元素选择器------ */ /*将div下所有的span子元素标签的字体大小设置为16px, 背景颜色设置为#DEB887*/ #d1>span{ font-size:18px; background:#DEB887; }
-
属性选择器(指定标签和标签属性),多个属性用多个[]来区分
格式:选择器[属性条件…][属性条件…]…{ css属性… }
根据元素及元素的属性条件来匹配元素
/* ------3.属性选择器------ */ /*为所有的文本输入框,设置背景颜色为pink,字体大小为30px,首行缩进30px*/ input[type='text'][name="username"]{ background:pink; font-size:30px; text-indent:30px; }
-
伪类选择器。
格式:选择器:状态{ 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; }
常用属性总结
-
文本相关属性
text-align:设置文本水平排列方式
left 居左,right 居右,center 居中
text-indent:设置文本首行缩进,单位是像素/百分比
text-decoration:设置文本的下划线样式,常见取值:
underline:有下划线
none:无下划线
text-shadow:设置文本阴影,取值:值1,值2,值3,值4;
值1:设置阴影水平偏移位置
值2:设置阴影垂直偏移位置
值3:设置阴影模糊程度
值4:设置阴影颜色
-
字体相关属性
font-size:字体大小
font-weight:字体粗细,取值:normal bold bolder
font-family:设置字体,“宋体”,“黑体”等
color:设置字体颜色
line-height:设置行高
-
背景相关属性
background-color:设置背景颜色
background-image:设置背景图片
background-position:设置背景图片的位置
background-repeat:设置背景图片是否以及如何排列
-
其他属性
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的方式
-
在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>
-
在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/>
-
元素名(标签名)选择器
$(“div”) – 匹配所有的div元素
$(“span”) – 匹配所有的span元素
-
类选择器
$(“div.mini”) – 匹配所有class为mini的div元素
-
ID选择器
$("#one") – 匹配id为one的元素
层级选择器
-
后代选择器
$(“div span”) – 匹配div内部的所有span后代元素
-
子元素选择器
$(“div>span”) – 匹配div内部的所有span子元素
-
相邻兄弟选择器
$("#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兄弟元素
基本过滤选择器
-
: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元素
-
: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应用
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的作用?
- 浏览器向服务器发送请求,服务器调用一个Servlet来处理
- Servlet负责对请求进行处理,处理的过程中可能需要连接并访问数据库,最终得出一个结果
- 通常Servlet不直接将结果响应给浏览器,而是由JSP或者html负责展示
- 最终要响应的结果由服务器负责响应给浏览器
开发Servlet程序
开发Servlet程序的步骤
- 写一个类,实现一个Servlet接口并实现其中的方法
- 在web应用的web.xml文件中配置Servlet对外访问的路径
使用eclipse创建web项目
-
创建一个web工程:在左侧窗口中,鼠标右键–new–Dynamic Web Project
-
接着会弹出窗口:
项目名 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
-
选中项目中的src目录,鼠标右键–new–Servlet
-
在弹出的窗口中:
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程序、访问测试
-
在运行servlet上点击右键–Run As–“1 Run on Server”
-
在弹出的窗口中,直接点击完成即可
-
运行结果出来后,复制系统浏览器的路径,到常用浏览器中粘贴访问
-
在运行的同时,web应用也会被发布(部署)到tomcat服务器中,如下:
运行的同时,web应用也会被发布到tomcat服务器中,如下:servers–服务器–项目
思考:
-
eclipse部署web应用到tomcat,那么部署的位置在哪里?如何修改这个位置
eclipse默认会将web应用发布到这个目录下:
workspace\.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps
如果要修改发布的路径,可以双击服务器,在弹出的窗口中找到如下图所示的位置,但是发现不能修改选项
可以将服务器中所有已发布的web应用从服务器移除,再在服务器上右键点击clean…,此时,回到上面的窗口,就可以修改其中的配置了:
-
通过eclipse部署到web应用到tomcat服务器,是如何实现部署的?或者eclipse是如何将web应用发布到服务器中的?
Servlet继承关系
-
servlet接口–定义一个servlet程序应该具备哪些功能
-
–GenericServlet抽象类,实现了Servlet接口,并且实现了其中大部分的方法,但是没有实现service方法,因为service是处理的核心方法,这个方法应该由开发人员自己来实现
-
HttpServlet抽象类,继承了GenericServlet类,也继承了其中的方法,同时还实现了父类没有实现的service方法,在service方法中,根据不同的请求方式调用不同的doXxx方法。例如请求方法是GET提交,将会调用doGet方法,如果请求时POST提交,将会调用doPost方法
因此,以后在开发Servlet时,可以写一个类,直接继承HttpServlet,并覆盖其中的doGet和doPost方法,分别来处理GET和POST请求即可(非必须)
-
-
servlet调用过程
request和response
request是代表http请求信息的对象,其中封装了浏览器发送过来的请求信息
response是代表http响应信息的对象,其中封装了将要发送给浏览器的响应信息
在服务器接收浏览器的请求之后,在调用service方法处理请求之前,服务器会创建request和response对象,分别用来封装请求和响应信息
request
获取请求参数
请求参数:
da哪个浏览器访问服务器时,发送给服务器的数据就是请求参数
比如:在登录时或者注册时,浏览器需要将用户名和密码等信息发送给服务器,这些发送给服务器的用户名和密码就是请求参数
如何获取请求参数?
request.getParameter(String name);
– 通过请求参数的名字,获取对应的参数值
request.getParameterValues();
– 通过请求参数的名字,获取对应的所有参数值组成的数组,返回的是一个字符串数组
如何处理请求参数的乱码问题?
-
如果是GET提交,并且tomcat是8.0及以后的版本,GET提交的中文参数是没有乱码的,因为tomcat服务器底层针对GET提交的参数乱码已经做了处理
-
但是如果是tomcat7.0及7.0之前的版本,GET提交的中文参数也是有乱码的。如何处理?
在tomcat服务器/conf/server.xml中修改端口的Connector标签上添加一个属性:
-
如果时POST提交,不管是哪个版本的tomcat服务器,POST提交的中文参数都是有乱码的,处理方式是,在任何获取参数的代码之前,添加一行设置:
//针对POST提交的参数乱码问题 request.setCharacterEncoding("utf-8"); //获取参数 String user = request.getParameter("username"); System.out.println(user);
请求转发、作为域对象
请求转发:资源跳转的一种方式,这种跳转对外是不可见的(浏览器看不见)。当浏览器发请求访问服务器中的一个资源(比如Servlet),而这个Servlet最终没有做出响应,而是将请求转交给另外一个资源(比如Servlet/JSP等),由另外的这个资源来做响应,那么将请求从一个资源转交给另外一个资源的过程就是请求转发。
实现转发代码:
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>
运行结果:
请求转发的特征:
- 转发前后是一次请求,一次响应
- 转发前后浏览器的地址没有发生变化
- 转发只能是同一个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”);
通过response.getWriter获取的流,向浏览器发送数据时,默认使用的编码是iso8859-1,而这个码表中没有中文字符,所以在发送中文数据时,如果使用默认的编码(iso8859-1),一定会出现乱码问题!
解决方法:response.setContentType(“text/html;charset=utf-8”);
- 通知服务器使用utf-8发数据给浏览器
- 通知浏览器也是用utf-8接收服务器发过来的数据