一、数据库
MySQL数据库管理系统
关系型数据库:多张能互相连接的二维表(正常的行列表格)组成的数据库
SQL通用语法
1.SQL可以单行或多行书写,以分号结尾
2.MySQL数据库的SQL语句不区分大小写,但关键字建议使用大写
3.注释 单行注释:1.-- 注释内容 2. #注释内容 多行注释:/* 注释 */
SQL分类
DDL操作数据库
DDL操作表
查询(Retrieve)
查询当前数据库下所有表名称
show tables;
查询表结构
desc 表名称;
创建(Create)
create table 表名(
字段名1 数据类型1,
字段名2 数据类型2,
...
字段名n 数据类型n
);
注意:最后一行末尾,不能加逗号
数据类型
1.age int
2.score double(总长度,小数点后保留的位数)
3.birthday date
4.name char(最大存储数) 如果最大储存数为10,我输入张三,后面会自动补8个空格,占满10个字符空间 存储性能高,浪费空间(空间换时间)
5.name varchar(最大存储数) 只会占需要用到的存储空间(每次都会计算具体要用多少字符空间) 存储性能低,节约空间(时间换空间)
删除(Delete)
删除表
drop table 表名;
删除表时判断表是否存在
drop table if exists 表名;
修改(Update)
DML
添加(insert)
修改(update)
1.修改表数据
update 表名 set 列名1=值1,列名2=值2,...[where 条件];
注意:修改语句中如果不加where条件,则将所有数据都修改
删除(delete)
删除数据
delete from 表名[where 条件];
注意:修改语句中如果不加where条件,则将所有数据都删除
-- 查询所有数据
SELECT
*
FROM
tb_user;-- 给指定列添加数据INSERT INTO 表名(列名1,列名2,...) VALUES(值1,值2,...);
INSERT INTO tb_user ( id, username )
VALUES
( 1, '张三' );
INSERT INTO tb_user ( id, username, `password` )
VALUES
( 2, '李四', 113448 );-- 给所有列添加数据,列名的列表可以省略的,但尽量不要去省略
INSERT INTO tb_user
VALUES
( 3, '李四', 113448 );
SELECT *from tb_user;
-- 修改数据 update 表名 set 列名1=值1,列名2=值2,...[where 条件];
update tb_user set `password`=10086 where username='李四';
-- 删除 delete from 表名[where 条件];
DELETE from tb_user where username='张三';
DQL查询数据
基础查询
条件查询
select 字段列表 from 表名 where 条件列表;
-- 删除stu表
DROP table if exists stu;
-- 创建stu表
CREATE TABLE stu(
id int,-- 编号
name varchar(20), -- 姓名
age int,--年龄
sex varchar(5),-- 性别
address varchar(100),-- 地址
math double(5,2),--数学成绩
english double(5,2),--英语成绩
hire_date date --入学时间
);
-- 添加数据
insert into stu(id,name,age,sex,address,math,english,hire_date)
VALUES
(1,'马云',55,'男','杭州',66,78,'1995-09-01'),
(2,'马化腾',45,'女','深圳',98,87,'1988-09-01'),
(3,'马克思',55,'男','香港',56,77,'1999-09-02'),
(4,'留白',20,'女','湖南',76,65,'1997-09-05'),
(5,'留情',20,'男','湖南',86,NULL,'1998-09-01'),
(6,'刘德华',57,'男','香港',99,99,'1998-09-01'),
(7,'张学友',22,'女','香港',99,99,'1988-09-01'),
(8,'德玛西亚',18,'男','南京',56,65,'1994-09-02');
select * from stu;
-- 条件查询===================
-- 1.查询年龄大于20岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age>20;
-- 2.查询年龄大于等于20岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age>=20;
-- 3.查询年龄大于等于20岁并且年龄小于等于30岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age>=20 and age<=30;select id,name,age,sex,address,math,english,hire_date from stu where age>=20 && age<=30;select id,name,age,sex,address,math,english,hire_date from stu where age between 20 and 30;
-- 4.查询入学日期在'1998-09-01'到'1999-09-01'之间的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where hire_date between '1998-09-01' and '1999-09-01';
-- 5.查询年龄等于18岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age=18;
-- 6.查询年龄不等于18岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age!=18;
select id,name,age,sex,address,math,english,hire_date from stu where age <> 18;
-- 7.查询年龄等于18岁或者年龄等于20岁或者年龄等于22岁的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where age=18 or age=20 or age=22;
select id,name,age,sex,address,math,english,hire_date from stu where age in(18,20,22);
-- 8.查询英语成绩为null的学员信息
-- 注意:null值的比较不饿使用 = != ,需要使用 is is not
select id,name,age,sex,address,math,english,hire_date from stu where english is null;
select id,name,age,sex,address,math,english,hire_date from stu where english is not null;
-- 模糊查询 like =============
/*
通配符:
1. _ :代表单个任意字符
2. % :代表任意个数字符
*/
-- 1.查询性'马'的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where name like '马%';
-- 2.查询第二个字是'化'的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where name like '_化%';
-- 3.查询名字中包含'德'的学员信息
select id,name,age,sex,address,math,english,hire_date from stu where name like'%德%';
排序查询
select 字段列表 from 表名 order by 排序字段名1[排序方式1],排序字段名2[排序方式2]...;
排序方式:
ASC:升序排序(默认值)
DESC:降序排列
注意:如果有多个排序条件,当前边的条件值一样时,才会根据第二个条件进行排序
-- 1.查询学生信息,按照年龄升序排序
select id,name,age,sex,address,math,english,hire_date from stu order by age asc;
-- 2.查询学生信息,按照数学成绩降序排列
select id,name,age,sex,address,math,english,hire_date from stu order by math DESC;
-- 3.查询学生信息,按照数学成绩降序排列,如果数学成绩一样,再按照英语成绩升序排列
select id,name,age,sex,address,math,english,hire_date from stu order by math DESC,english ASC;
分组查询
聚合函数:将一列数据作为一个整体,进行纵向计算
count(列名) 统计数量
max(列名) 最大值
min(列名) 最小值
sum(列名) 求和
age(列名) 平均值
select 聚合函数名(列名) from 表;
注意:null值不参与所有聚合函数运算
-- 1.统计班级一共有多少个学生
select count(id) from stu;
-- 2.查询数学成绩的最高分
select max(math) from stu;
-- 3.查询数学成绩的最低分
select min(math) from stu;
-- 4.查询数学成绩的总分
select sum(math) from stu;
-- 5.查询数学成绩的平均分
select avg(math) from stu;
分组查询
select 字段列表 from 表名 [where 分组前条件限定] group by 分组字段名 [having 分组后条件过滤];
注意:分组之后,查询的字段为聚合函数和分组字段,查询其他字段无任何意义
-- 1.查询男同学和女同学各自的数学平均分
select sex,avg(math) from stu group by sex;
-- 2.查询男同学和女同学各自的数学平均分,以及各自人数
select sex,avg(math),count(id) from stu group by sex;
-- 3.查询男同学和女同学各自的数学平均分,以及各自人数,要求:分数低于70分的不参与分组
select sex,avg(math),count(id) from stu where math>70 group by sex;
-- 4.查询男同学和女同学各自的数学平均分,以及各自人数,要求:分数低于70分的不参与分组,分组后人数大于2
select sex,avg(math),count(id) from stu where math>70 group by sex having count(id)>2;
where和having区别:
执行时机不一样:where是分组之前进行限定,不满足where条件,则不参与分组,而having是分组后对结果进行过滤
可判断的条件不一样:where不能对聚合函数进行判断,having可以
执行顺序:where>聚合函数>having
分页查询
select 字段列表 from 表名 limit 起始索引,查询条目数;
起始索引:从哪开始查 从0开始
select * from stu;
-- 1.从0开始查询,查询3条数据
select * from stu limit 0,3;
-- 2.每页显示3条数据,查询第1页数据
select * from stu limit 0,3;
-- 3.每页显示3条数据,查询第2页数据
select * from stu limit 3,3;
-- 4.每页显示3条数据,查询3页数据
select * from stu limit 6,3;
计算公式:起始索引=(当前页码-1)*每页显示的条数
约束
约束是作用于表中列上的规则,用于限制加入表中的数据
注意:MySQL里面没有检查约束
drop table if exists emp;
-- 员工表
create table emp(
id int primary key auto_increment,-- 员工id,主键且自增长
ename varchar(50) not null unique,-- 员工姓名,非空且唯一
joindate date not null,-- 入职日期,非空
salary double(7,2) not null,-- 工资,非空
bonus double(7,2) default 0 -- 奖金,如果没有奖金默认为0
);
insert into emp(id,ename,joindate,salary,bonus) values(1,'张三','1999-11-11',8000,5000);
-- 主键约束: 非空且唯一
-- 自动增长:auto_increment:当列是数组类型并且是唯一约束
insert into emp(ename,joindate,salary,bonus) values('张三2','1999-11-11',8000,5000);
insert into emp(id,ename,joindate,salary,bonus) values(null,'张三3','1999-11-11',8000,5000);
select * from emp;
外键约束
添加外键
[constraint][外键名称] foreign key(外键列名) references 主表(主表列名)
drop table if exists dept;
drop table if exists emp;
-- 部门表
CREATE TABLE dept(
id int PRIMARY KEY auto_increment,
dep_name varchar(20),
addr varchar(20)
);
-- 员工表
CREATE TABLE emp(
id int PRIMARY KEY auto_increment,
name VARCHAR(20),
age int,
dep_id int,
-- 添加外键 dep_id,关联dept表的id 主键
CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES dept(id)
);
-- 添加两个部门
INSERT INTO dept(dep_name,addr) VALUES('研发部','广州'),('销售部','深圳');
-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO emp(name,age,dep_id) VALUES
('张三',20,1),
('李四',20,1),
('王五',20,1),
('赵六',20,2),
('孙七',20,2),
('周八',18,2);
select * from emp;
-- 删除外键
ALTER table emp drop foreign key fk_emp_dept;
-- 建完表后,添加外键
alter table emp add CONSTRAINT fk_emp_dept foreign key(dep_id) REFERENCES dept(id);
数据库设计
软件研发步骤
多表关系
一对多:部门表和员工表
在多的一方建议外键,指向一的一方主键
多对多:商品和订单
建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
/*
多对多:
*如:订单和商品
*一个商品对应多个订单,一个订单包含多个商品
实现方式:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
*/
-- 删除表
drop table if exists tb_order_goods;
drop table if exists tb_order;
drop table if exists tb_goods;
-- 订单表
create table tb_order(
id int primary key auto_increment,
payment double(10,2),
payment_type tinyint,
status tinyint
);
-- 商品表
create table tb_goods(
id int primary key auto_increment,
title varchar(100),
price double(10,2)
);
-- 订单商品中间表
create table tb_order_goods(
id int primary key auto_increment,
order_id int,
goods_id int,
count int
);
-- 建完表后,添加外键
alter table tb_order_goods add constraint fk_order_id foreign key (order_id) references tb_order(id);
alter table tb_order_goods add constraint fk_order_id foreign key(order_id) references tb_goods(id);
一对一:用户 用户详情
一对一关系多用于表拆分,将一个实体中经常使用的字段放一张表,不经常使用的字段放另一张表,用于提升查询性能
实现方式:在任意一方加入外键,关联另一方外键,并且设置外键为唯一(unique)
多表查询
-- 多表查询
select * from emp,dept;
-- 笛卡尔积:有A,B两个集合,取A,B所有的组合情况 A有4个,B有8个,总共就有32种组合
-- 消除无效数据
-- 查询emp和dept的数据,emp.dep_id=dept.did
select * from emp,dept where emp.dep_id=dept.did;
内连接:
-- 隐式内连接
selevt * from emp,dept where emp.dep_id=dept.did;
-- 查询emp的name,gender,dept表的dname
select emp.name,emp.gender,dept.dname from emp,dept where emp.dep_id=dept.did;
-- 给表起别名 as可以省略
select t1.name,t1.gender,t2.dname from emp as t1,dept as t2 where t1.dep_id=t2.did;
-- 显示内连接 inner可省略
select * from emp inner join dept on emp.dep_id=dept.did;
外连接:
-- 左外连接
select * fron emp left [outer] join dept on empldep_id=dept.did;
-- 右外连接
select * fron emp right [outer] join dept on empldep_id=dept.did;
子查询:查询中嵌套查询,称嵌套查询为子查询
单行单列
-- 1.查询猪八戒的工资
select salary from emp where name="猪八戒";
-- 2.查询工资高于猪八戒的员工信息
select * from emp where salary>3600;
select * from emp where salary>(select salary from emp where name="猪八戒");
多行单列
-- 查询“财务部”和“市场部”所有员工的信息
select did from dept where dname="财务部" or dname="市场部";
select * from emp where dep_id in (select did from dept where dname="财务部" of dname="市场部");
多行多列
查询入职日期是2011-11-11之后的员工信息和部门信息
查询入职日期是2011-11-11之后的员工信息
select * from emp where join_date>'2011-11-11';
select * from (select * from emp where join_date>'2011-11-11') as t1 ,dept where t1.dep_id=dept.did;
count(*)统计数量
事务
事务包含了一组数据库操作命令,这一组命令要么同时成功,要么同时失败
-- 开启事务
start transaction; 或者 begin;
-- 提交事务
commit;
-- 回滚事务
rollback;
事务四大特征
drop table if exists account1;
-- 创建账户表
create table account1(
id int primary key auto_increment,
name varchar (10),
money double(10,2)
);
-- 添加数据
insert into account1(name,money) values('张三',1000),('李四',1000);
select * from account1;
-- 转账操作
-- 开启事务
begin;
-- 本窗口打开还会是1000 500,但用别的窗口打开仍然是1000 1000,临时的
-- 1.查询李四的余额
-- 2.李四金额-500
-- update 表名 set 字段=新值… where 条件
update account1 set money =money-500 where name='李四';
出错了...
-- 3.张三金额+500
update account1 set money =money+500 where name='张三';
-- 提交事务 将事务实体化,别的窗口打开也可以看到变化
commit;
-- 回滚事务 回滚到开启事务之前的状态
rollback;
-- 1.查询事务的默认提交方式
select @@autocommit;
-- 结果为1为默认提交,0则需要commit手动提交,MySQ为自动提交
二、JDBC
简介
JDBC就是使用Java语言操作关系型数据库的一套API
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/*
*JDBC快速入门
*/
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
String url="jdbc:mysql://127.0.0.1:3306/db1";
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql
String sql="update account set money=2000 where id=1";
//4.获得执行sql对象 statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//返回受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
API详解
DriverManager(驱动管理类)
作用:1.注册驱动(DriverManagerr类里有registerDriver) 可省略
2.获取数据库连接getConnection(url,user,password)
url:连接路径 jdbc:mysql://ip地址(或域名):端口号/数据库名称?参数键值对1&参数键值对2
user:用户名
password:密码
public class JDBCDemo02_DriverManager {
/*
* JDBC API 详解:DriverManager
*/
public static void main(String[] args) throws Exception{
//2.获得连接:如果连接的是本机mysql并且端口是默认的3306 可以简化书写
String url="jdbc:mysql:///db1?useSSl=false" ;//useSSl=false禁用安全连接,让系统不会爆红色提醒,减少程序占用内存空间
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
}
}
Connection(数据库连接对象)
作用:
1.获取执行SQL对象
Statement createStatement()
2.管理事务
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,极为开启事务
提交事务:commit()
回滚事务:rollback()
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*
*JDBC API详解:Connection
*/
public class JDBCDemo3_Connection {
public static void main(String[] args) throws Exception {
// 2.获取连接
String url="jdbc:mysql:///db1?useSSL=false";
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义SQL
String sql1="update account set money =3000 where id=1";
String sql2="update account set money =3000 where id=2";
//4.获取执行sql的对象 statement
Statement stmt = conn.createStatement();
//开启事务
try {
//开启事务
conn.setAutoCommit(false);
//5.执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6.处理结果
System.out.println(count1);
int count2 = stmt.executeUpdate(sql2);
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception e) {
//回滚事务
conn.rollback();
e.printStackTrace();
}
//7.释放资源
stmt.close();
conn.close();
}
}
Statement(执行类)
作用:1.执行SQL语句
int executeUpdate(sql):执行DML、DDL语句
返回值:(1)DML语句影响行数(2)DDL执行成功后也可能返回0
2.Result executeQuery(sql):执行DQL语句
返回值:ResultSet结果焦对象
package com.itheima.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*
*JDBC API 详解:Statement
*/
public class JDBCDemo4_Statement {
@Test //测试类,要给这个类单独导入一个包alt+回车
public void testDML() throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
String url="jdbc:mysql://127.0.0.1:3306/db1?useSSL=false";
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql
String sql="update account set money=2000 where id=5";
//4.获得执行sql对象 statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//返回受影响的行数
//6.处理结果
//System.out.println(count);
if (count>0) {
System.out.println("修改成功");
}else
{
System.out.println("修改失败");
}
//7.释放资源
stmt.close();
conn.close();
}
}
ResultSet(结果集对象)
作用:1.封装DQL查询语句的结果
ResultSet stmt.executeQuery(sql) 执行DQL语句,返回ResultSet对象
获取查询结果
boolean next():(1)将光标从当前位置向前移动一行(2)判断当前行是否为有效行(是否有数据)
getxxx(参数):获取数据
xxx:数据类型 如:int getint(参数) ; String getString(参数)
package com.itheima.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/*
*JDBC API 详解:Result
*/
public class JDBCDemo05_ResultSet {
/*
*执行DQL查询语句
*/
@Test
public void testResultSet() throws Exception{
//2.获得连接
String url="jdbc:mysql:///db1?useSSL=false";
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql
String sql="select * from account";
//4.获取statement对象
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//6.处理结果,遍历rs中所有的数据
//6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
//6.2 获取数据
int id=rs.getInt(1);//也可以getInt("id)
String name=rs.getString(2);
double money=rs.getDouble(3);
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("-----------------");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
PreparedStatement
作用:1.预编译SQL语句并执行,预防SQL注入问题
2:对敏感字符进行转义 在单引号 前面放\
SQL注入:通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法
用户登录密码连接数据库
package com.itheima.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/*
*用户登录
*/
public class JDBCDemo06_UserLogin {
@Test
public void testResultSet() throws Exception{
//2.获取连接
String url="jdbc:mysql:///db1?useSSL=false";
String username="root";
String password ="1234";
Connection conn = DriverManager.getConnection(url,username,password);
//接收用户输入的用户名和密码
String name="zhangsan";
String pwd="1fsfsaf";
String sql="select * from tb_user where username = '"+name+"' and password ='"+pwd+"'";
//获取stmt对象
Statement stmt = conn.createStatement();
//执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断是否成功
if (rs.next()){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//释放资源
rs.close();
stmt.close();
conn.close();
}
}
sql注入
String pwd="'or'1'='1 ";
利用字符串拼成恒等式
解决sql注入问题 利用占位符替代字符
package com.itheima.jdbc;
import org.testng.annotations.Test;
import java.sql.*;
/*
*API详解:PrepareStatement
*/
public class JDBCDemo7_PrepareStatement {
@Test
public void testPreparedStatement() throws Exception{
//获取连接
String url="jdbc:mysql:///db1?useSSL=false";
String username="root";
String password ="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接收用户输入用户名和密码
String name="zhagnsan";
String pwd="sadfsaf";
//定义sql
String sql="select * from tb_user where username =? and password =?";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql
ResultSet rs = pstmt.executeQuery();
//判断登录是否成功
if (rs.next())
{
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//释放资源
rs.close();
pstmt.close();
conn.close();
}
}
数据库连接池
一个容器,里面有提前开好的连接conn,有用户来就从容器里拿一个连接conn用,用完也不关闭,而是再次放入容器中
Druid(德鲁伊)连接池
标准接口:DataSource
获得连接
Connection getConnection()
package druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
/*
*Druid数据库连接池演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream(""));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获得数据库连接Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
JDBC练习
环境准备和查询
package example;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.testng.annotations.Test;
import pojo.Brand;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Properties;
/*
*品牌数据的增删改查操作
*/
public class BrandTest {
/*
*查询所有
* 1.SQL:select * from tb_brand;
* 2.参数:不需要
* 3.结果List<Brand>
*/
@Test
public void testSelectAll() throws Exception{
//1.获取连接Connection
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream(""));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义SQL
String sql="select * from tb_brand";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
//5.执行SQL
ResultSet rs = pstmt.executeQuery();
//6.处理结果 List<Brand> 封装Brand对象,装载List集合
Brand brand=null;
ArrayList<Brand> brands = new ArrayList<>();
while (rs.next()){
//获取数据
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
//封装Brand对象
brand = new Brand();
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
//装载集合
brands.add(brand);
}
System.out.println(brands);
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
}
添加
insert into tb_brand( , , , )values(?,?,?,?)
public class BrandTest {
/*
*添加
* 1.SQL:insert into tb_brand(brand_name,company_name,ordered,description,status)values(?,?,?,?,?);
* 2.参数:需要 除了id之外的所有参数信息
* 3.结果:boolean
*/
@Test
public void testAdd() throws Exception{
//接收页面提交的参数
String brandName="香飘飘";
String companyName="香飘飘";
int ordered=1;
String description="绕地球一圈";
int status=1;
//1.获取连接Connection
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream(""));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义SQL
String sql="insert into tb_brand(brand_name,company_name,ordered,description,status)values(?,?,?,?,?);";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
//5.执行SQL
int count = pstmt.executeUpdate();//影响的行数
//6.处理结果
System.out.println(count>0);
//7.释放资源
pstmt.close();
conn.close();
}
}
修改
update tb_brand
set brand_name=?,
company_name=?,
ordered=?,
description=?,
status=?
where id=?
public void testUpdate() throws Exception{
//接收页面提交的参数
String brandName="香飘飘";
String companyName="香飘飘";
int ordered=1000; //排序越大排的越靠前,可以正常打广告用
String description="绕地球三圈";
int status=1;
int id=4;
//1.获取连接Connection
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream(""));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义SQL
String sql="update tb_brand\n" +
" set brand_name=?,\n" +
" company_name=?,\n" +
" ordered=?,\n" +
" description=?,\n" +
" status=?\n" +
" where id=?";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id) ;
//5.执行SQL
int count = pstmt.executeUpdate();//影响的行数
//6.处理结果
System.out.println(count>0);
//7.释放资源
pstmt.close();
conn.close();
}
}
删除
delete from tb_brand where id=?
三、Maven
Maven基本使用
compile:编译
clean:清理
test:测试
package:打包
install:安装
Maven生命周期:一次构建过程经历了多少个事件
同一生命周期内,执行后边的命令,前边的所有命令会自动执行
Maven坐标
Maven中的坐标是资源的唯一标识
组成:
groupld:定义当前Maven项目隶属组织名称(通常是域名反写,com.itheima)
artifactld:定义当前Maven项目名称(通常是模块名称,例如order-service、goods-service)
version:定义当前项目版本号
使用坐标导入jar包
1.在pom.xml中编写<dependencies>标签
2.在<dependencies>标签中使用<dependency>引入坐标
3.定义坐标的groupld,artifactld,version
4.点击刷新按钮,使坐标生效(可在设置里选择自动刷新)
依赖管理
<scope><scope> 默认值:compile
四、MyBatis
JavaEE三层架构:表现层、业务层、持久层
MyBatis使一款优秀的持久层框架,用于简化JDBC开发
查询user表中所有数据
执行sql
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
Mapper代理开发
UseMapper useMapper = sqlSession.getMapper(UseMapper.class);
List<User> users = useMapper.selectAll();
五、html
1.基础标签
2.图片音频视频标签
3.超链接标签
<a> 定义超链接,用于链接到另一个资源
href:指定访问资源的URL
target:指定打开资源的方式( _self:默认值,在当前页面打开 _blank:在空白页面打开)
4.列表标签
<ol> 有序列表 用1 2 3标识
<ul> 无序列表 用黑点标识
<li> 列表项
type:设置项目符号
5.表格标签
<table> 表格
<tr> 行
<td> 单元格
<th> 表头单元格(第一行 一般比较特殊)
table:定义表格( border: 表格边框的宽度 width:表格的宽度 cellspacing:单元格之间的空白)
tr:定义行 ( align:表格行的内容对齐方式)
td:定义单元格 (rowspan:单元格可以横跨的行数 colspanl:单元格可以横跨的列数)
6.布局标签
<div> 定义html文档中一个区域部分,经常与CSS一起使用,用来布局网页
<sapn> 用于组合元素
7.表单标签
表单:在网页中主要负责数据采集功能,使用<form>标签
表单项(元素):不同类型的input元素,下拉列表、文本域等
<form> 表单
<input> 表单项,通过type属性控制输入形式
<label> 表单项定义标注
<select> 下拉列表
<option> 下拉列表的列表项
<textarea> 文本域
form:
action:指定表单数据提交的URL
* 表单项数据想要被提交,就必须指定其name属性
method:指定表单提交的方式
1.get:默认值
*请求参数会拼接在URL后边
*url的长度有限制 4kb
2.post:
*请求参数会在http请求协议的请求体中
*请求参数无限制
六、css
选择器
七、JavaScript
基础语法
1.引入方式
1.内部脚本:将JS代码定义在HTML页面中(js代码必须位于<script></script>标签之间)
<script>
alert("hello,js");
</script>
在html文档中可以在任意地方放置任意数量<script>
一般将脚本置于<body>元素底部,可改善显示速度,因为脚本的执行会拖慢显示
2.书写语法
1.区分大小写 2.结尾分号可有可无
<script>
window.alert("hello js");//写入警告框
document.write("hell js2");//写入html页面
console.log("hello js3");//写入浏览器的控制台
</script>
3.变量&数据类型
var关键字(相当于全局变量)
var test=20;
test="张三"
let关键字(只在let关键字所在代码块内有效,且不允许重复声明)
const关键字声明只读常量
使用typeof运算符可以获取数据类型
alert(typeof age)
4.运算符
== 1.判断类型是否一样,如果不一样,则进行强制类型转换 2.再去比较其值
=== 1.判断类型是否一样,如果不一样,直接返回false 2.再去比较其值
类型转化
其他类型转为number:
1.string:按照字符串的字面值,转为数字,如果字面值不是数字,则转为NaN,一般使用parseInt
2.boolean:true转为1 false转为0
其他类型转为boolean:
1.numbei:0和NaN转为false,其他的数组转为true
2.string:空白字符串转为false,其他的字符串转为true
3.null:false
4.underfined:false
5.函数
function关键字
function add(a,b){
return a+b;
}
var add=fuction(a,b){
return a+b;
}
js中,函数调用可以传递任意个数参数
对象
Array
var 变量名=new Array(元素列表);
var 变量名=[元素列表]
var arr=new Array(1,2,3);
var arr=[1,2,3];
js中的数组相当于java中集合,变长变类型
String
var 变量名=s;
方法
charAt() 返回在指定位置的字符
indexOf() 字母第一次出现的位置
trim() 去除字符串前后两端的空白字符
自定义对象
var 对象名称={
属性名称1:属性值1,
属性名称2:属性值2,
函数名称:function(形参列表){}
};
BOM
浏览器对象模型
组成:Window:浏览器窗口对象
Navigator:浏览器对象
Screen:屏幕对象
History:历史记录对象
Loaction:地址栏对象
Window
浏览器窗口对象
获取:直接使用window,其中window.可以省略
window.alert("abc");
属性:获取其它BOM对象
方法:
alert() 显示带有一段消息和一个确认按钮的警告框
confirm() 显示带有一段消息以及确认按钮和取消按钮的对话框(点击确定按钮会返回true,在取消返回false)
setInterval() 按照指定的周期(以毫秒计)来调用函数或者计算表达式 (循环执行)
setTimeout() 在指定的毫秒数后调用函数或计算表达式(只执行一次)
History
历史记录
获取:使用window.history获取,window.可以省略
window.history.方法();
history.方法();
方法:
back() 加载history列表中的前一个URL
forward() 加载history列表中的下一个URL
Location
地址栏对象
获取:使用window.location获取,其中window.可以省略
window.location.方法();
location.方法();
属性:
href 设置或返回完整的URL
DOM
文档对象模型
讲标记语言的各个组成部分封装为对象
Document:整个文档对象
Element:元素对象
Attribute:属性对象
Text:文本对象
Comment:注释对象
获取Element对象
元素对象
获取:使用Document对象的方法来获取
1.getElementById:根据id属性值获取,返回一个Element对象
2.getElementsByTagName:根据标签名称获取,返回Element对象数组
3.getElementsByName:根据name属性值获取,返回Element对象数组
4.getElementByClassName:根据class属性值获取,返回Element对象数组
常见HTML Element对象的使用
查文档
事件监听
事件:HTML事件是发生在HTML元素上的“事情”
eg:1.按钮被点击 2.鼠标移动到元素之上 3.按下键盘按键
事件监听:JavaScript可以在事件被侦测到时执行代码
事件绑定
一、通过HTML标签中的事件属性进行绑定
<input type="button" onclick='on()'>
function on(){
alert("我被点了");
}
二、通过DOM元素属性绑定
<input type="button" id="btn">
document.getElementById("btn").onclick=function(){
alert("我被点了");
}
常见事件
查文档
表单验证
正则表达式
正则表达式定义了字符串组成的规则
定义:
注意:不要加引号,因为不是字符串
var reg=/^\w{6,12}$/;
var reg=new RegExp("^\\w{6,12}$");
方法:
test(str):判断指定字符串是否符合规则,返回true或false
八、Web核心
B/S架构:Browser/Server,浏览器/服务器架构模式,特点:客户端只需要浏览器,应用程序的逻辑和数据都存储再服务器端。浏览器只需要请求服务器,获取Web资源,服务器把Web资源发送给浏览器即可
浏览器请求服务器: HTTP协议:定义通信规则
Web服务器;负责解析HTTP协议,解析请求数据,并发送响应数据
HTTP
请求数据格式
请求行:请求数据的第一行。其中GET表示请求方式,/表示请求资源路径,HTTP/1.1表示协议版本
请求头:第二行开始,格式为key:value形式
常见的HTTP请求头:
Host:表示请求的主机名
User-Agent:浏览器版本
Accept:表示浏览器能接受的资源类型,如text/*,image/*或者*/*(表示所有)
Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页(中,英...)
Accept-Encoding:表示浏览器可以支的压缩类型
请求体:POST请求的最后一部分,存放请求参数(与请求体有一行空行隔开)
GET请求和POST请求区别:
1.GET请求请求参数在请求行中,没有请求体,POST请求请求参数在请求体中
2.GET请求请求参数大小有限制(URL长度有限制),POST没有
相应数据格式
相应行:相应数据的第一行。其中HTTP/1.1表示协议版本,200表示相应状态码,OK表示状态码描述
200 OK 客户端请求成功,即处理成功
404 Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了(改路径)
500 Internal Server Error 服务器发生不可预期的错误,服务器出异常(修改Java代码)
响应头:第二行开始,格式为key:value形式
Content-Type:表示该响应内容的类型,例如text/html,image/jpeg
Content-Length:表示响应内容的长度(字节数)
Content-Encoding:表示该响应压缩算法,例如gzip
Cache-Control:指示客户端应如何缓存(缓存到本地下次就可以直接从本地打开减少响应时间),例如max-age=300(表示可以最多缓存300s)
响应体:最后一部分,存放响应数据(与响应头有一行空行隔开)
Tomcat
基本使用
启动:双击:bin\startup.bat
关闭:Crtl+C:正常关闭
配置:修改端口号:conf/server.xml(HTTP协议默认端口号为80,如果将Tomcat端口号改为80,则将来访问Tomcat不用输入端口号)
启动:端口号冲突找到对应程序,将其关闭
部署项目:将项目放到webapps目录下(一般JavaWeb项目会被打成war包,然后将war包放到webapps目录下,Tomcat会自动解压缩war文件)
项目结构:
创建MavenWeb项目:
IDEA中使用Tomcat
Servlet
Servlet是Java提供的一门动态(不同用户访问看到的效果就不一样,个性化)web资源开发技术
Servlet其实就是一个接口,由web服务器运行Servlet
快速入门
demo
@WebServlet("/demo1")
public class ServletDemo1 implements Servlet {
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("servlet hello world");
}
.xml
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
<packaging>war</packaging>
执行流程
生命周期
@WebServlet(urlPatterns = "/demo2")
public class ServletDemo3 implements Servlet {
private ServletConfig config;
public void init(ServletConfig servletConfig) throws ServletException {
this.config=config;
//初始化方法
//1.调用时机:默认情况下Servlet被第一次访问时调用
//2.调用次数:1次
System.out.println("init...");
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//提供服务
//调用时机:每一次Servlet被访问时,调用
//调用次数:多次
System.out.println("servlet hello world");
}
public String getServletInfo() {
return null;
}
//返回一些关于Servlet的信息,作者版权版本
public void destroy() {
//销毁方法
//1.调用时机:内存释放或者服务器关闭的时候,Servlet对象会被销毁,调用
//2.调用次数:1次
System.out.println("destroy");
}
public ServletConfig getServletConfig() {
return config;
}
}
体系结构
@WebServlet("/demo5")
public class ServletDemo5 extends MyHttpServlet {
@Override
protected void doGet(ServletRequest req, ServletResponse res) {
System.out.println("get...");
}
@Override
protected void doPost(ServletRequest req, ServletResponse res) {
System.out.println("post...");
}
}
public class MyHttpServlet implements Servlet {
public void init(ServletConfig servletConfig) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//根据请求方式的不同,进行分别的处理(get/post)
HttpServletRequest request=(HttpServletRequest) req;
//1.获取请求方式
String method = request.getMethod();
//2.判断
if("GET".equals(method)){
//get方式的处理逻辑
doGet(req,res);
}else if("POST".equals(method))
{
//post方式的处理逻辑
doPost(req,res);
}
}
protected void doPost(ServletRequest req, ServletResponse res) {
}//protected子类可见
protected void doGet(ServletRequest req, ServletResponse res) {
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
Servlet urlPattern配置
Servlet要想被访问,必须配置其访问路径(urlPattern)
1.一个Servlet可以配置多个urlPattern
@WebServlet(urlPatterns={"/demo1","demo2"})
2.配置规则
优先级:精确路径>目录路径>扩展名路径>/*>/
Request(请求)&Response(响应)
Request:获取请求数据
Response:设置响应数据
Request继承体系
Request获取请求数据
请求行
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET/request-demo1/req1?username=zhangsan HTTP/1.1
//String getMethod(): 获取请求方式:GET
String method = req.getMethod();
System.out.println(method);//GET
//String getContextPath():获取虚拟目录:request-demo1
String contextPath = req.getContextPath();
System.out.println(contextPath);
//StringBuffer getRequrstURL():获取URL(统一资源定义符):http://localhost:8080/request-demo1/req1
StringBuffer url = req.getRequestURL();
System.out.println(url);
//StringBuffer getRequestURI();获取URI(统一资源标识符):request-demo1/req1
String uri = req.getRequestURI();
System.out.println(uri);
//String getQueryString(): 获取请求参数(GET方式):username=zhangsan
String queryString = req.getQueryString();
System.out.println(queryString);
}
请求头
//---------------
//获取请求头:user-agent:浏览器的版本信息
String agent = req.getHeader("user-agent");
System.out.println(agent);
请求体
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取post 请求体:请求参数
//1.获取字符输入流
BufferedReader br = req.getReader();
//2.读取数据
String line = br.readLine();
System.out.println(line);
}
Request对象获得请求参数
Map <String,String[]> getParameterMap():获取所有参数集合
String[] getParameterValues(String name):根据名称获取参数值(数组)
String getParameter(String name):根据名称获取参数值(单个值)
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求逻辑
System.out.println("get....");
//1.获取所有参数的map集合
Map<String, String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
//username:zhangsan lisi
System.out.print(key+":");
//获取值
String[] values = map.get(key);
for (String value : values) {
value= new String(value.getBytes("ISO-8859-1"), "utf-8");
System.out.print(value+" ");
}
System.out.println();
}
System.out.println("---------");
//2.根据key获取参数值,数组
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3.根据key.获取单个参数值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//POST请求逻辑
this.doGet(req,resp);
}
}
请求参数中文乱码
POST解决方案:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.解决乱码:POST.getReader()
request.setCharacterEncoding("UTF-8");//设置字符输入流的编码
//2.获取username
String username = request.getParameter("username");
System.out.println("解决乱码前:"+username);
}
GET解决方案:
{ //2.获取username
String username = request.getParameter("username");
System.out.println("解决乱码前:"+username);
//3.GET,获取参数的方式:getQueryString
//乱码原因;tomcat进行URL解码,默认的字符集ISO-8859-1
/* //3.1 先对乱码数据进行编码:转为字节数组
byte[] bytes = username.getBytes("ISO-8859-1");
//3.2 字节数组解码
username = new String(bytes,"utf-8");*/
username=new String(username.getBytes("ISO-8859-1"),"utf-8");
System.out.println("解决乱码后:"+username);
}
请求转发
forward:一种在服务器内部的资源跳转方式(类似流水线)
实现方式:
req.getRequestDispatcher("资源B路径").forward(req,resp);
请求转发资源间共享数据:使用Request对象
1.void setAttribute(String name,Object o):存储数据到request域中
2.Object getAttribute(String name): 根据key,获取值
3.void removeAttribute(String name):根据key,删除键值对
请求转发特点
1.浏览器地址栏路径不发生变化
2.只能转发到当前服务器的内部资源
3.一次请求,可以在转发的资源间使用request共享数据
Response设置响应数据功能介绍&完成重定向
重定向(Redirect):一种资源跳转方式
实现方式:
resp.setStatus(302);
resp.setHeader("location","资源B的路径")
简化方式:
resp.sendRedirect("资源B的路径");
重定向特点(与请求转发相反):
1.浏览器地址栏路径发生变化
2.可以重定向到任意位置的资源(服务器内部,外部均可)
3.两次请求,不能在多个资源使用request共享数据
资源路径问题
浏览器使用:需要加虚拟路径(项目访问路径)
服务端使用:不需要加虚拟目录
//动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/resp2");
Response响应字符&字节数据
字符:
使用:
1.通过Response对象获取字符输出流
PrintWriter writer=resp.getWriter();
2.写数据
writer.write("aaa");
字节:
使用:
1.通过Response对象获取字符输出流
ServletOutStream outputStream=resq.getOutputStream();
2.写数据
outputStream.write(字节数据);
IOUtils工具类使用
1.导入坐标
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
2.使用
IOUtills.copy(输入流,输出流);
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.读取文件
FileInputStream fis = new FileInputStream("e://a.jpg");
//2.获取response字节输出流
ServletOutputStream os = response.getOutputStream();
//3.完成流的copy
/* byte[] buff = new byte[1024];
int len=0;
while ((len=fis.read(buff))!=-1){
os.write(buff,0,len);
}
*/
IOUtils.copy(fis,os);
fis.close();
}
案例
用户登录:
用户注册:
避免重复开资源,创一个工具类,里面放static块(只能被执行一次)
JSP
Java服务端页面
JSP=HTML+Java
快速入门
JSP脚本
JSP脚本用于在JSP页面内定义Java代码
1.<%...%>:内容会直接放到_jspService()方法之中
2.<%=...%>:内容会放到out.print()中,作为out.print()的参数
3.<%!...%>:内容会放到_jspService()方法之外,被类直接包含
<%@ page import="pojo.Brand" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %><%--
Created by IntelliJ IDEA.
User: LYQ
Date: 2022/11/26
Time: 20:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
List<Brand> brands = new ArrayList<Brand>();
brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));
brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));
brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
<tr align="center">
<td>1</td>
<td>三只松鼠</td>
<td>三只松鼠</td>
<td>100</td>
<td>三只松鼠,好吃不上火</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
for (int i = 0; i < brands.size(); i++) {
Brand brand = brands.get(i);
%>
<tr align="center">
<td><%=brand.getId()%></td>
<td><%=brand.getBrandName()%></td>
<td><%=brand.getCompanyName()%></td>
<td><%=brand.getOrdered()%></td>
<td><%=brand.getDescripition()%></td>
<td><%=brand.getStatus()%></td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
EL表达式
用于简化JSP页面内的Java代码
语法:${expression}
${brands}:获取域中存储的key为brands的数据
JavaWeb中的四大域对象:1.page 当前页面有效 2.request 当前请求有效 3.session 当前会话有效 4.application 当前应用有效
JSTL标签
使用标签取代JSP页面上的Java代码
1.导入坐标
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
2.在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3.使用
<c:if></c:if> if判断
<body>
<%--
c标签
--%>
<c:if test="${status==1}">
<h1>启用</h1>
</c:if>
<c:if test="${status==0}">
<h1>禁用</h1>
</c:if>
</body>
<c:forEach>:相当于for循环
items:被遍历的容器
var:遍历产生的临时变量
在page directive中的isELIgnored属性用来指定是否忽略。格式为: <%@ page isELIgnored="true|false"%> 如果设定为真,那么JSP中的表达式被当成字符串处理。比如下面这个表达式${1000 % 10}, 在isELIgnored="true"时输出为${1000 % 10},而isELIgnored="false"时输出为100。Web容器默认isELIgnored="false"
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<c:forEach items="${brands}" var="brand" varStatus="status">
<tr align="center">
<%-- <td>${brand.id}</td>--%>
<td>${status.count}</td>
<%-- status.index代表从0开始 status.count代表从1开始--%>
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.oedered}</td>
<td>${brand.description}</td>
<c:if test="${brand.status==1}">
<td>启用</td>
</c:if>
<c:if test="${brand.status!=1}">
<td>禁用</td>
</c:if>
<td>${brand.status}</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</c:forEach>
</table>
<hr>
<c:forEach begin="0" end="10" step="1" var="i">
<a href="#"> ${i}<br> </a>
</c:forEach>
</body>
</html>
MVC模式和三层架构
MVC是一种分层开发的模式:
M:Model,业务模型,处理业务
V:View,视图,界面展示
C:Controller,控制器,处理请求,调用模型和视图
三层架构:
数据访问层:dao/mapper
业务逻辑层:service
表现层:web/controller
案例
1.创建新的模块brand_demo,引入坐标
2.创建三层架构的包结构
3.数据库表tb_brand
4.实体类Brand
5.MyBatis基础环境:Mybatis-config.xml(mybatis核心配置文件,1.类起别名2.环境准备3.扫描mapper(mapper接口)) BrandMapper.xml BrandMapper接口
service层作用:真正大型的项目并非只是根据页面的条件进行增删改查的。 查询的时候页面传递给service层的只是简单的一些查询条件,但是页面需要显示的查询结果的数据并不在同一个对象(或者说表)中,这就需要service层进行一些逻辑处理了,比如将这些查询条件进行拆分、组合用以查询不同的数据,然后再将这些不同的数据进行整合反馈给前台页面显示。
提高代码复用性
查询所有
解决实体类属性名称和字段名称不一致
配置映射文件
BrandMapper.xml
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
添加
修改
回显数据:讲原来的数据展示给用户
修改数据
会话跟踪技术
Cookie:将数据放在客户端 Session:将数据放在服务端
Cookie基本使用
客户端会话技术,将数据保存到客户端,以后每次请求都携带Cookie数据进行访问
发送Cookie
1.创建Cookie对象,设置数据
Cookie cookie=new Cookie("key","value");
2.发送Cookie到客户端:使用response对象
response.addCookie(cookie);
获取Cookie
3.获取客户端携带的所有Cookie,使用request对象
Cookie[] cookies=request.getCookies();
4.遍历数组,获取每一个Cookie对象:for
5.使用Cookie对象方法获取数组
cookie.getName();
cookie.getValue();
Cookie原理
响应头:set-cookie
请求头:cookie
Cookie存活时间
默认情况下,Cookie存在浏览器内存中,当浏览器关闭,内存释放,则cookie被销毁
setMaxAge(int seconds):设置Cookie存活时间
1.正数:讲Cookie写入浏览器所在的电脑的硬盘,持久化存储。到时间自动删除
2.负数:默认值
3.零:删除对应Cookie
Cookie存储中文
如需要存储,需要进行转码:URL编码
package com.itheima.web.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.net.URLEncoder;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//发送cookie
//1.创建cookie
//Cookie cookie = new Cookie("username","zs");
String value="张三";
//URL编码
value = URLEncoder.encode(value, "UTF-8");
System.out.println("存储数据"+value);
Cookie cookie = new Cookie("username", value);
//设置存活时间 1周7天 直接放进去可自动算出来
cookie.setMaxAge(60*60*24*7);
//2.发送Cookie。response
response.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
package com.itheima.web.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取cookie
//1.获取Cookie数组
Cookie[] cookies = request.getCookies();
//2.遍历数组
for (Cookie cookie : cookies) {
//3.获取cookie数据
String name = cookie.getName();
if ("username".equals(name))
{
String value = cookie.getValue();
//URL编码
value = URLDecoder.decode(value, "UTF-8");
System.out.println(name+":"+value);
break;
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
Session基本使用
总是和客户端交互可能会不安全
将数据保存到服务端
JavaEE提供HttpSession接口,来实现一次会话的多次请求间数据共享功能
使用:
1.获取Session对象
HttpSession session=request.getSession();
2.Session对象功能
void setAttribute(String name,Object o) //存储数据到session域中
Object getAtrribute(String name)//根据key,获取值
void removeAttribute(String name) //根据key,删除该键值对
Session原理
Session是基于Cookie实现的
Session钝化、活化:
不能因服务器的重启导致数据丢失
钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中
活化:再次去启动服务器后,从文件中加载数据到Session中
Session销毁:
浏览器关闭,Session获得的就不是同一个了,而cookie可以写到电脑硬盘中,长时间储存数据
默认情况下,无操作,30min自动销毁
可通过web.xml配置
<session-config>
<session-timeout>100</session-timeout>
</session-config>
主动销毁数据(登录退出)
session.invalidate();
package com.itheima.web.session;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/demo1")
public class SessionDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//存储到Session中
//1.获取Session中
HttpSession session = request.getSession();
//2.存储数据
session.setAttribute("username","zs");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
package com.itheima.web.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/demo2")
public class SessionDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取数据:从session中
//1.获取Session对象
HttpSession session = request.getSession();
//销毁
session.invalidate();
//2.获取数据
Object username = session.getAttribute("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
小结:
区别:
存储位置:Cookie是将数据存储在客户端,Session将数据存储在服务端
安全性:Cookie不安全(传来传去),Session安全
数据大小:Cookie最大3KB,Session无大小限制
存储时间:Cookie可以长期存储,Session默认30分钟
服务器性能:Cookie不占服务器资源,Session占用服务器资源
Cookie用来保证用户在未登录状态下的,Session保护用户登录后的数据
Filter
过滤器
可以把对资源的请求拦截下来,从而实现一些特殊的功能
一般完成一些通用的操作(进入到后面资源都需要用到的操作,写一遍代码就行,比如说登录)
eg:权限控制、统一编码处理、敏感字符处理
Fileter快速入门
1.定义类,实现Filter接口(先接),并重写其所有方法
2.配置Filter拦截资源的路径:在类上定义@WebFilter注解
3.在doFilter方法输出一句话,并放行
package com.itheima.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
//设置需要拦截哪些东西,什么都想拦/*
@WebFilter("/*")
public class FilterDemo implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1.放行前,对request数据进行处理
System.out.println("FilterDemo...");
//放行
filterChain.doFilter(servletRequest,servletResponse);
//2.放行后,对Response数据进行处理
System.out.println("3.FilterDemo");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
Filter执行流程
资源访问完成后,还会回到Filter中
执行放行前逻辑->放行->访问资源->执行放行后逻辑
Filter使用细节
Filter拦截路径配置
@WebFilter("/*")
public class FilterDemo
拦截具体的资源:/index.jsp:只有访问index.jsp时才会被拦截
目录拦截:/user/* :访问/user下的所有资源,都会被拦截
后缀名拦截:*.jsp:访问后缀名为jsp的资源,都会被拦截
拦截所有:/*:访问所有资源,都会被拦截
过滤器链
一个Web应用中,可以配置多个过滤器,这多个过滤器称为过滤器链
优先级按照过滤器类名(字符串)的自然排序 字典序
Listener
监听器:可以监听就是在application,session,request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件
1.定义类,实现ServletContextListener接口
2.在类上添加@WebListener注解
package com.itheima.web.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//加载资源
System.out.println("ContextLoaderListener...");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
AJAX
作用:1.与服务器进行数据交换:通过AJAX可以给服务器发送请求,并获取服务器响应的数据
使用AJAX和服务器进行通信,就可以使用HTML+AJAX来替换JSP页面
2.异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想,用户名是否可用校验
同步和异步
AJAX快速入门
1.编写AjaxServlet,并使用response输出字符串
2.创建XMLHttpRequest对象:用于和服务器交换数据
3.向服务器发送请求
4.获取服务器响应数据
Axios异步框架
对原生AJAX进行封装,简化书写
<script src="js/axios-0.18.0.js"></script>
<script>
// //1.get
// axios({
// method:"get",
// url:"http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan"
// }).then(function (resp)
// {
// alert(resp.data);
//
//2.post
//1.get
axios({
method:"post",
url:"http://localhost:8080/ajax-demo/axiosServlet",
data:"username=zhangsan"
}).then(function (resp)
{
alert(resp.data);
})
</script>
package com.itheima.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/axiosServlet")
public class AxiosServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get....");
//1.接收请求参数
String username = request.getParameter("username");
System.out.println(username);
//2.响应数据
response.getWriter().write("hello axios~");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post...");
this.doGet(request, response);
}
}
Axios请求方式别名
JSON
JavaScript对象表示法 作为数据载体
JSON基础语法
定义
var 变量名={
"key1":value1,
"key2":value2,
};
value的数据类型为:数字,字符串,逻辑值(false或true),数组(在方括号中),对象(在花括号中),null
获取数据:变量名.key
JSON数据和Java对象转换
浏览器
请求数据:JSON字符串转为Java对象
响应数据:Java对象转为JSON字符串
Fastjson库
1.导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.18</version>
</dependency>
2.Java对象转JSON
String jsonStr=JSON.toJSONString(obj);
3.JSON字符串转Java对象
User user=JSON.parseObjecet(jsonStr,User.class)
Vue
Vue是一套前端框架,免除原生JavaScript中的DOM操作,简化书写
基于MVVN思想,实现数据的双向绑定
Vue快速入门
../代表上一层目录
../../代表上上层目录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input v-model="username">
<!-- 插值表达式 上面的模型一变,取出来的数值就跟着变化-->
{{username}}
</div>
<script src="../js/vue.js"></script>
<script>
//1.创建vue的核心对象
new Vue({
el:"#app",
data() {
return{
username:""
}
}
})
</script>
</body>
</html>
Vue常用指令
html标签上带有v-前缀的特殊属性
v-bind:为HTML标签绑定属性值,如设置href,css样式等(直接写href会把程序写死,这样写可以随意改变)
v-model:为表单元素上创建双向数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<a v-bind:href="url">点击一下</a>
<br>
<a :href="url">点击一下</a>
<input v-model="url">
</div>
<script src="../js/vue.js"></script>
<script>
//1.创建Vue核心对象
new Vue({
el:"#app",
data() {
return{
username:"",
url:"https://www.baidu.com"
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="button" value="一个按钮" v-on:click="show()">
<input type="button" value="一个按钮" @click="show()">
</div>
<script src="../js/vue.js"></script>
<script>
new Vue({
el:"#app",
methods:{
show(){
alert("我被点了...")
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="button" value="一个按钮" v-on:click="show()">
<input type="button" value="一个按钮" @click="show()">
<div v-if="count==3">div1</div>
<div v-else-if="count==4">div2</div>
<div v-else>div3</div>
<hr>
<div v-show="count==3">v-show</div>
<input v-model="count">
</div>
<script src="../js/vue.js"></script>
<script>
new Vue({
el:"#app",
data(){
return{
count:3
}
},
methods:{
show(){
alert("我被点了...")
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-for="(addr,i) in addrs">
{{i+1}}--{{addr}} <br>
</div>
</div>
<script src="../js/vue.js"></script>
<script>
new Vue({
el:"#app",
data(){
return{
username:"",
url:"https://www.baidu.com",
count:3,
addrs:["北京","上海","徐州"]
}
},
methods:{
show(){
alert("我被点了...")
}
}
})
</script>
</body>
</html>
Vue生命周期
Vue案例
查询所有
新增品牌
v-model输入的值产生变化,模型自动产生变化(获取值再赋值的代码就不用写了)
Element
基于Vue的网站组件库,用于快速构建网页
Element官网
快速入门
1.引入Element的文件
先引入vue在引入element-ui
<script src="../js/vue.js"></script>
<script src="../element-ui/lib/index.js"></script>
<link rel="stylesheet" href="../element-ui/lib/theme-chalk/index.css">
2.创建Vue核心对象
3.官网复制Element组件代码
布局