02-janycode.github.io
2021-07-26 09:52:27 3 举报
AI智能生成
JavaSE、JavaWeb、Java分布式开发学习
作者其他创作
大纲/内容
Tools
JDK1.8-API中文版
Notepad++
Eclipse
常规使用
* 创建项目:File > new > project > Java Project
* src下创建包:[右键]new > Package
* package下创建类:[右键]new > Class (.java文件)
* 修改编辑字体:Windows > Preferences > Gerenal > Appearance > Colors and Fonts > Basic > Text Font > Edit > "Microsoft YaHei Mono"-11
* 修改输出字体:Windows > Preferences > Gerenal > Appearance > Colors and Fonts > Debug > Text Font > Edit > "Microsoft YaHei Mono"-11
* 重置窗体排布:Windows > Perspective > Reset Perspective
* src下创建包:[右键]new > Package
* package下创建类:[右键]new > Class (.java文件)
* 修改编辑字体:Windows > Preferences > Gerenal > Appearance > Colors and Fonts > Basic > Text Font > Edit > "Microsoft YaHei Mono"-11
* 修改输出字体:Windows > Preferences > Gerenal > Appearance > Colors and Fonts > Debug > Text Font > Edit > "Microsoft YaHei Mono"-11
* 重置窗体排布:Windows > Perspective > Reset Perspective
导入项目
* 导入项目:File > Import > General > Existing Projects into Workspace > Browse > [项目根文件夹] > finish
附加源码
* 默认正确,无需改动,如需改动,参考步骤:
Windows > Preferences > Java > Installed JRES > 选中JRE > Edit > 选中..\rt.jar > Source Attachment > External location > 找到src.zip
Windows > Preferences > Java > Installed JRES > 选中JRE > Edit > 选中..\rt.jar > Source Attachment > External location > 找到src.zip
快捷键
* Ctrl+1 快捷修复
* Ctrl+D 快捷删除行
* Shift+Enter 无视光标直接跳入下一行
* Ctrl+F11 一键运行
* Alt+↑/↓ 快速移动单/多行
* Ctrl+Alt+↑/↓ 快速复制单/多行
* Ctrl+M 将当前代码编辑框放大/恢复
* Alt+/ 快速补全代码
>> sout:System.out.println();
* Ctrl+/ 快速注释单/多行和恢复(单行注释符 // )
* Ctrl+Shift+/ 快速注释单/多行和恢复,需选中 (多行注释符 /* */)
* /** 快速创建函数的javadoc文档注释
* Ctrl+Shift+F 格式化代码(注意印象笔记&搜狗输入法的快捷键冲突)
* Ctrl+E 弹出快速文件选择窗然后上下选择
* Alt+Shift+W 选择第一个Package Explorer即可快速定位
* Alt+Shift+R 然后修改即可修改所有相同变量
* Ctrl+Q 返回上一个Ctrl+鼠标单击跳转的原始位置
* F3 在关键字上按,可以跳转进入源码
* Alt+←/→ 浏览F3跳转源码的轨迹
* Ctrl+Shift+O 快速导包:导入需要的包同时去掉无用的包
* Alt+Shift+Z 选中代码行后,快速创建try-catch块
* Ctrl+O 快速显示OutLine悬浮窗,搜索和浏览成员方法
* Ctrl+2,L 为调用方法时返回值的本地变量赋值
* Ctrl+D 快捷删除行
* Shift+Enter 无视光标直接跳入下一行
* Ctrl+F11 一键运行
* Alt+↑/↓ 快速移动单/多行
* Ctrl+Alt+↑/↓ 快速复制单/多行
* Ctrl+M 将当前代码编辑框放大/恢复
* Alt+/ 快速补全代码
>> sout:System.out.println();
* Ctrl+/ 快速注释单/多行和恢复(单行注释符 // )
* Ctrl+Shift+/ 快速注释单/多行和恢复,需选中 (多行注释符 /* */)
* /** 快速创建函数的javadoc文档注释
* Ctrl+Shift+F 格式化代码(注意印象笔记&搜狗输入法的快捷键冲突)
* Ctrl+E 弹出快速文件选择窗然后上下选择
* Alt+Shift+W 选择第一个Package Explorer即可快速定位
* Alt+Shift+R 然后修改即可修改所有相同变量
* Ctrl+Q 返回上一个Ctrl+鼠标单击跳转的原始位置
* F3 在关键字上按,可以跳转进入源码
* Alt+←/→ 浏览F3跳转源码的轨迹
* Ctrl+Shift+O 快速导包:导入需要的包同时去掉无用的包
* Alt+Shift+Z 选中代码行后,快速创建try-catch块
* Ctrl+O 快速显示OutLine悬浮窗,搜索和浏览成员方法
* Ctrl+2,L 为调用方法时返回值的本地变量赋值
快速生成代码
Alt+Shift+S 弹出源码选项
+o 完成构造方法
+r 添加geter和seter
+s 添加覆盖Object父类toString()方法
+v 继承覆盖方法
+c 继承构造方法
+m 成员的方法
+h 添加 hashcode() 和equals()
IntelliJ IDEA
基本使用
Web项目
IDEA创建Web项目
如果已打开项目 File >> Close Project
初识启动界面中 + Create New Project
初识启动界面中 + Create New Project
Java Enterprise >> ☑Web Application >> Next
IDEA生成war包
配置:
Project Structure图标 >> Artifacts >> +新增Web Application: Arichive选择当前项目xxx:war >> OK
Project Structure图标 >> Artifacts >> +新增Web Application: Arichive选择当前项目xxx:war >> OK
生成:
Build >> Build Artifacts >> 选择xxx:war点击Build >> out/artifacts/xxx_war/xxx_war.war
Build >> Build Artifacts >> 选择xxx:war点击Build >> out/artifacts/xxx_war/xxx_war.war
部署:
将xxx_war.war包放在 Tomcat 的 webapps 目录下,启动服务器会自动解压该web项目,便于直接访问
将xxx_war.war包放在 Tomcat 的 webapps 目录下,启动服务器会自动解压该web项目,便于直接访问
UML类图
Ctrl+Shift+S 打开全局设置 >> Tools 工具 >> Diagrams 图表 >>
Java Class Diagrams >> ☑Fields属性 ☑Constructors构造方法 ☑Methods成员方法
Ctrl+Alt+Shift+U 显示类图到新标签栏(Ctrl+/按1:1比例显示,Ctrl按住可拖动,Alt按住为放大镜)
Java Class Diagrams >> ☑Fields属性 ☑Constructors构造方法 ☑Methods成员方法
Ctrl+Alt+Shift+U 显示类图到新标签栏(Ctrl+/按1:1比例显示,Ctrl按住可拖动,Alt按住为放大镜)
MySQL Console 关键字大写
Settsings(Ctrl+Alt+S) -->Editor --> Code Style --> SQL --> MySQL 将keywords设置为大写(To upper)
快捷键
窗口菜单
Ctrl+Alt+S 全局设置菜单窗口
Ctrl+P 方法的参数提示
Ctrl+Q 方法的注释+声明提示
Ctrl+F12 显示当前文件的结构(快速跳转)
Ctrl+[ / ] 跳转{ }作用域开始 / 结束位置
Ctrl+E 显示最近打开过的文件
Ctrl+Tab 切换编辑文件或项目树,Ctrl需按住
Alt+←/→ 前后切换编辑的文件标签,结合Ctrl+Tab摆脱鼠标
Alt+` 弹出版本控制窗口,如history、Git等
Alt+1 切到Project项目窗口(已打开则收缩) >> ESC 切回代码区
Alt+2 切到Favorites收藏夹窗口(已打开则收缩)
Alt+4 切到Run运行窗口(已打开则收缩)
Alt+6 切到TODO窗口(已打开则收缩)
Alt+7 切到Structure结构窗口(已打开则收缩) - Ctrl+F12更好
Alt+8 切到Service窗口(已打开则收缩),如MySQL运行结果
Alt+0 切到Message窗口(已打开则收缩)
Ctrl+B 跳转进入调用方法
Ctrl+Alt+B 跳转进入继承的子类方法
Ctrl+Shift+B 跳转进入接口的实现类方法
Ctrl+ALt+←/→ 返回跳转的上一步或下一步
Ctrl+Alt+U 显示类的继承/实现关系图
Ctrl+Alt+B 显示继承子类或实现类
Ctrl+Alt+P 显示被继承父类或被实现的接口
F4 跳转到实现源码
-----------------------------------------------------------
Ctrl+P 方法的参数提示
Ctrl+Q 方法的注释+声明提示
Ctrl+F12 显示当前文件的结构(快速跳转)
Ctrl+[ / ] 跳转{ }作用域开始 / 结束位置
Ctrl+E 显示最近打开过的文件
Ctrl+Tab 切换编辑文件或项目树,Ctrl需按住
Alt+←/→ 前后切换编辑的文件标签,结合Ctrl+Tab摆脱鼠标
Alt+` 弹出版本控制窗口,如history、Git等
Alt+1 切到Project项目窗口(已打开则收缩) >> ESC 切回代码区
Alt+2 切到Favorites收藏夹窗口(已打开则收缩)
Alt+4 切到Run运行窗口(已打开则收缩)
Alt+6 切到TODO窗口(已打开则收缩)
Alt+7 切到Structure结构窗口(已打开则收缩) - Ctrl+F12更好
Alt+8 切到Service窗口(已打开则收缩),如MySQL运行结果
Alt+0 切到Message窗口(已打开则收缩)
Ctrl+B 跳转进入调用方法
Ctrl+Alt+B 跳转进入继承的子类方法
Ctrl+Shift+B 跳转进入接口的实现类方法
Ctrl+ALt+←/→ 返回跳转的上一步或下一步
Ctrl+Alt+U 显示类的继承/实现关系图
Ctrl+Alt+B 显示继承子类或实现类
Ctrl+Alt+P 显示被继承父类或被实现的接口
F4 跳转到实现源码
-----------------------------------------------------------
无敌通用
Alt+Insert 插入一切
双击Shift+Tab 搜索一切
双击Shift+Tab 搜索一切
快速编辑
-----------------------------------------------------------
main+Tab 生成main方法,类名下 m 即可
sout+Tab 生成输出语句,so 即可
new Xxxx( ).var 快速生成引用赋值
fori 快速生成for循环 - i 整数遍历
iter 快速生成增强for循环 - foreach
itar 快速生成array for循环 - 字符串遍历
itit 快速生成iterator迭代-while( ) next( )
itco 快速生成Collection迭代 - for
.foreach 快速foreach循环
Ctrl+X 删除+剪切当前行
Ctrl+C 高亮+复制当前行
Ctrl+D 立即复制当前行到下一行
Ctrl+Shift+↑/↓ 快速移动代码行
Ctrl+/ 或 Ctrl+Shift+/ 单行 或 多行注释
Ctrl+O 重写方法(继承)
Ctrl+i 实现方法(实现接口) Alt+Enter代替
Ctrl+Shift+U 大小写转换
Ctrl+Shift+J 合并选中的行变1行
Ctrl+Alt+L 自动缩进及格式化代码
Ctrl+"+/-" 当前方法展开、折叠
Ctrl+Shift+"+/-" 全部展开、折叠
Alt+/ 代码提示(默认自动提示)
F2 快速定位到错误代码
Alt+Enter 自动修正波浪线错误
Alt+Insert 生成代码(构造、get/set等)
Ctrl+Alt+T 生成try-catch等各种代码块
Ctrl+Alt+O 优化导入的类和包(顺序)
main+Tab 生成main方法,类名下 m 即可
sout+Tab 生成输出语句,so 即可
new Xxxx( ).var 快速生成引用赋值
fori 快速生成for循环 - i 整数遍历
iter 快速生成增强for循环 - foreach
itar 快速生成array for循环 - 字符串遍历
itit 快速生成iterator迭代-while( ) next( )
itco 快速生成Collection迭代 - for
.foreach 快速foreach循环
Ctrl+X 删除+剪切当前行
Ctrl+C 高亮+复制当前行
Ctrl+D 立即复制当前行到下一行
Ctrl+Shift+↑/↓ 快速移动代码行
Ctrl+/ 或 Ctrl+Shift+/ 单行 或 多行注释
Ctrl+O 重写方法(继承)
Ctrl+i 实现方法(实现接口) Alt+Enter代替
Ctrl+Shift+U 大小写转换
Ctrl+Shift+J 合并选中的行变1行
Ctrl+Alt+L 自动缩进及格式化代码
Ctrl+"+/-" 当前方法展开、折叠
Ctrl+Shift+"+/-" 全部展开、折叠
Alt+/ 代码提示(默认自动提示)
F2 快速定位到错误代码
Alt+Enter 自动修正波浪线错误
Alt+Insert 生成代码(构造、get/set等)
Ctrl+Alt+T 生成try-catch等各种代码块
Ctrl+Alt+O 优化导入的类和包(顺序)
查找替换
-----------------------------------------------------------
双击Shift+Tab 查找一切
Ctrl+N+N 全局搜索Class
Ctrl+F 当前文件执行查找
Ctrl+Shift+F 整个项目查找文本
Ctrl+R 当前文件执行替换
Ctrl+W 自动按语法选中代码(递增范围)
Shift+F6 批量重命名同1个变量名
Ctrl+G 定位行
Ctrl+Alt+←/→ 前后跳转编辑过的位置
Alt+F7 查看函数/变量/类的所有引用到的地方
F4 当前类中查找变量的定义位置
Ctrl+Shift+F7 高亮显示选中的相同文本,ESC取消高亮
双击Shift+Tab 查找一切
Ctrl+N+N 全局搜索Class
Ctrl+F 当前文件执行查找
Ctrl+Shift+F 整个项目查找文本
Ctrl+R 当前文件执行替换
Ctrl+W 自动按语法选中代码(递增范围)
Shift+F6 批量重命名同1个变量名
Ctrl+G 定位行
Ctrl+Alt+←/→ 前后跳转编辑过的位置
Alt+F7 查看函数/变量/类的所有引用到的地方
F4 当前类中查找变量的定义位置
Ctrl+Shift+F7 高亮显示选中的相同文本,ESC取消高亮
编译运行
-----------------------------------------------------------
Ctrl+Shift+F10 编译运行当前文件目标
Shift+ESC 关闭运行结果显示窗口【通用】
Ctrl+Shift+F10 编译运行当前文件目标
Shift+ESC 关闭运行结果显示窗口【通用】
插件
Translation
谷歌翻译插件
Ctrl+Shift+Y 可快捷翻译
Ctrl+Shift+X 可将中文翻译英文后替换(变量取名)
Ctrl+Shift+Y 可快捷翻译
Ctrl+Shift+X 可将中文翻译英文后替换(变量取名)
CamelCase
大/小/驼峰/下划线切换
Alt+Shift+U 来回切换字符串样式,直到满意
Alt+Shift+U 来回切换字符串样式,直到满意
SequenceDiagram
生成方法调用序列图
方法名上右键选择 Sequence Diagram
方法名上右键选择 Sequence Diagram
GenerateAllSetter
生成局部变量的所有set方法调用
变量上 Alt+Enter
变量上 Alt+Enter
Key Promoter X
右侧折叠小窗记录常用操作,显示快捷键提示
Jclasslib Bytecode Viewer
查看字节码文件
View >> Show ByteCode With Jclasslib
View >> Show ByteCode With Jclasslib
Gson Format
直接类内 Alt+Insert 选最后一个
或者类内 Alt+S 贴入json字符串,自动生成属性+get/set方法
或者类内 Alt+S 贴入json字符串,自动生成属性+get/set方法
Easy Code
右侧小窗 Database 数据库中连接后
右键 表名 选择 Easy Code >> Generate Code 自动生成数据映射关系的包和类
右键 表名 选择 Easy Code >> Generate Code 自动生成数据映射关系的包和类
Code Glance
代码编辑区右侧缩略图,同Sublime Text
GamelCase
对单词组合命名的变量/方法/类名使用:
Alt + Shift + U 可以调整不同方式命名,不停按6种直到满意。
Alt + Shift + U 可以调整不同方式命名,不停按6种直到满意。
Alibaba Java Coding Guidelines
阿里巴巴 Java 编程规范,自动提示/警告/报错
Alt + Enter 修复
Alt + Enter 修复
SQLyog
装好MySQL后,该客户端工具只需要输入密码即可使用。
工具 >> 首选项 >> 字体编辑器设置
Navicat
Hbuilder[X]
Hbuilder
Java实现,集成插件。
HbuilderX
C++实现,没有集成插件,更快更轻量。
插件安装:工具 >> 插件安装
快捷键方案:工具 >> 预设快捷键方案切换 >> Intellij IDEA/Webstorm
快捷键
Ctrl+/ 快速注释
Ctrl+N 快速新建
Ctrl+N 快速新建
JavaSE
环境搭建
概述
特点
面向对象
模拟现实世界,解决现实问题。
简单
Java有虚拟机,内置了垃圾收集器(GC),自动完成内存空间的管理。
跨平台
跨操作系统(Windows<C#>,Unix-Linux,MacOS,Solaris)、服务器、数据库。
由来
1995年推出
1996年发布JDK1.0
2009年被Oracle收购
2014年由Oracle发布Java 8.0<JDK1.8>
1996年发布JDK1.0
2009年被Oracle收购
2014年由Oracle发布Java 8.0<JDK1.8>
分类
JavaSE
Java Platform Standard Edition (Java平台标准版) CoreJava
JavaEE
Java Platform Enterprise Edition (Java平台企业版) 企业级开发
JavaME
Java Platform Micro Edition (Java平台微小版) Java最初的定位(机顶盒)
运行机制
先编译,再解释。
*.java(源文件) -> 编译 -> *.class(字节码文件) -> 执行 -> Win/Unic/MacOS/Others-(JVM)
Java设计理念:Write Once Run Anywhere.
名词解释
JVM
(Java Virtual Machine)虚拟机:使用软件在不同操作系统中模拟相同的环境。
JRE
(Java Runtime Environment)运行环境:包含JVM和解释器,完整的Java运行环境。
JDK
(Java Development Kit)开大环境:包含JRE[JVM+解释器] + 类库 + 开发工具包(编译器+调试工具)。
环境搭建
JDK获取
oracle官网获取,JDK1.8使用最为广泛。
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
JDK安装
非C盘
路径不带中文或空格
JDK包含JRE可跳过不装JRE
建议:D:\Java
JDK环境变量配置
win+E >> 右键(空白处) >> 属性 >> 环境变量
* 新建系统变量:
变量名:JAVA_HOME
变量值:D:\Java\jdk1.8.0_231 (找到实际安装路径)
变量名:JAVA_HOME
变量值:D:\Java\jdk1.8.0_231 (找到实际安装路径)
* 新建系统变量:
变量名:CLASS_PATH
变量值:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
变量名:CLASS_PATH
变量值:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
* 编辑Path变量:
变量名:Path
变量值:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; (末尾添加)
变量名:Path
变量值:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; (末尾添加)
验证:cmd命令窗口中输入"javac -version"
常用DOS命令
更换盘符:d:
查看当前目录下的文件和文件夹:dir
创建文件夹:mkdir 文件夹名字
进入文件夹:cd 文件夹名字
返回上一级目录:cd ..
清空屏幕:cls
删除文件:del 文件名
删除文件夹:rd 文件夹名称
退出:exit
查看当前目录下的文件和文件夹:dir
创建文件夹:mkdir 文件夹名字
进入文件夹:cd 文件夹名字
返回上一级目录:cd ..
清空屏幕:cls
删除文件:del 文件名
删除文件夹:rd 文件夹名称
退出:exit
第1个Java程序
源码
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, Java!!!");
}
}
public static void main(String[] args) {
System.out.println("Hello, Java!!!");
}
}
编译
javac HelloWorld.java
运行
java HelloWorld
类的阐述
* 同一个源文件中可以定义多个类
* 相同源文件中的多个类编译后会生成各自的.class文件
* 一个类中只能有一个主函数main,每个类都可以有各自的主函数main
* public修饰的类成为公开类,要求类名与文件名必须相同,包括大小写
* 一个源文件中只能有一个public公开类
* 相同源文件中的多个类编译后会生成各自的.class文件
* 一个类中只能有一个主函数main,每个类都可以有各自的主函数main
* public修饰的类成为公开类,要求类名与文件名必须相同,包括大小写
* 一个源文件中只能有一个public公开类
Package(包)
作用:类似文件夹,用于管理归纳字节码(.class)文件。
语法:package 包名;
多级:package 包名.包名;
位置:必须写在源文件的第一行。
带包编译:javac -d 目录名 源文件.java (会自动创建package包目录)
带包运行:java 包名.类名 (包名+类名又称全限定名)
doc文档生成
生成外部文档:javadoc -d 目录名 源文件.java
文档注意事项:
1.源文件编码问题,中文使用utf-8;
2.主要查看index.html文件
1.源文件编码问题,中文使用utf-8;
2.主要查看index.html文件
编码规范
终极参考:《阿里巴巴JAVA开发手册.pdf》
语言基础
变量
计算机内存中一块存储空间,是存储数据的基本单位
组成部分
数据类型
变量名
值
声明方式
先声明,再赋值
数据类型 变量名;
变量名 = 值;
变量名 = 值;
声明并赋值
多个同类型变量的声明与赋值
数据类型
基本数据类型
整数
byte
1个字节 -128 ~ 127
short
2个字节 -32768 ~ 32767
int
4个字节 -2^31 ~ 2^31-1
Java中任何一个整数,默认的类型为int,如果整数超过int取值范围,则均报错为过大的整数
long
8个字节 -2^63 ~ 2^63-1
long类型的赋值整数如果超过了int类型取值范围,则需要在数字后加 "L" 以标记为long类型
小数
float
4个字节 Float.MIN_VALUE ~ Float.MAX_VALUE
如果使用单精度float类型,则需要在数字后面加"F"表示单精度值
double
8个字节 Double.MIN_VALUE ~ Double.MAX_VALUE
Java中任意一个小数默认类型为双精度类型double
布尔
boolean
1个字节(根据具体环境) true / false
Java中的boolean类型变量不能参与算术运算!
字符
char
2个字节
转义字符 \
\' \" \\ \n \t
赋值
通过字符直接赋值【常用】
引用数据类型
字符串
String
任何""之间的内容都是字符串,包括空格
数组
对象
类型转换
自动类型转换
两种类型兼容,目标类型大于源类型
强制类型转换
两种类型兼容,目标类型小于源类型
转换规则
整数长度足够,数据完整
整数长度不够,数据截断
小数强转整数,数据截断
字符整数互转,数据完整
保证正整数转换成字符,可以正常显示
boolean不可与其他类型转换
自动类型提升
提升优先级规律:double << float << long < int << short/byte
两个操作数中有一个为优先级中的类型,计算结果提升为优先级中对应类型
任何类型与String相加(+)时,实为拼接,结果自动提升为String
【坑】num1+num2+string1:两个操作数为数值时,相加;两个操作数中有一个为String时,拼接。
运算符
算术运算符
+ - * / %
赋值运算符
= += -= *= /= %=
关系运算符
> < >= <= == !=
逻辑运算符
&& || !
三元运算符
布尔表达式 ? 结果1 : 结果2
控制台输入
1.导包
导包语法:import 包名.类名;
功能: 将外部class文件功能引入到自身文件中
位置: jdk1.8.0_121\jre\lib\rt.jar 压缩包中
import java.util.Scanner
2.声明
Scanner 类型的变量
Scanner input = new Scanner(System.in);
3.接收
输入类型
.nextInt(); // 获得整数
.nextDouble(); // 获得小数
.next(); // 获得字符串
.next().charAt(0); // 获得字符串的第一个字符
.nextDouble(); // 获得小数
.next(); // 获得字符串
.next().charAt(0); // 获得字符串的第一个字符
如果输入了不匹配的数据,则会产生 java.util.InputMismatchException 异常
TestScanner.java
选择与分支结构
概念:根据已知条件进行逻辑判断,满足条件执行操作
选择结构
基本if选择结构
if-else选择结构
多重if选择结构
适用于区间判断
嵌套if选择结构
语法正确、任意嵌套
分支结构
switch-case
可判断:byte,short,int,char,String(JDK7+)
switch中多个case的取值不可以相同
switch自动向下贯穿的特性,如需中止使用break关键字
局部变量
概念:声明在函数内部的变量,必须先赋值再使用
作用范围:从定义行开始到所在的代码块结束
注意:多个变量在一个重合的作用范围内,不可出现重名
循环结构
概念:通过某个条件,重复执行一段逻辑代码
基本结构
while循环
首次即有入口条件,适用于循环次数明确的情况
先判断,再执行。
次数:0-n
do-while循环
首次没有入口条件,适用于循环次数不明确的情况
先执行,再判断。
次数:1-n
for循环
首次即有入口条件,适用于循环次数明确的情况
初始部分只执行一次,且可以省略
次数:0-n
流程控制关键字
break
终止循环,跳出当前层级循环(1层)
跳出switch结构、跳出循环结构
continue
结束本次,跳过当前层级循环(1层),进入下一次
函数
概念:实现特定功能的一段代码,可以反复使用。
设计:遵循单一职能原则,一个函数只做一件事
规则:一个类中可以定义多个函数,函数之间是并列关系,不可嵌套
格式:
public static void 函数名称 () {
// 函数主体
}
// 函数主体
}
调用:函数名();
参数:
调用函数时,所传入的数据被称为"参数"
定义
public static void 函数名称 (函数形参) { // 形参 等价于 局部变量的声明
// 函数主体
}
// 函数主体
}
调用:函数名(实际参数); // 实参 等价于 局部变量的赋值操作
Tips:【字符串比较】
== 默认比较的地址值,不是字符串内容
str1.equals(str2); 含义:比较s1中存储的字符串是否与s2相同, true相同
!str1.equals(str2); 含义:比较s1中存储的字符串是否与s2不同, true不同
返回值和返回值类型
定义返回值类型:基本数据类型、引用数据类型、void
return value; // 函数可以返回一个结果,类型必须与函数定义的返回值一致
一个函数只能有一个返回值,如果函数中包含分支条件,需要保证所有的分支都有返回值
return 的两种用法
return value; // 表示结束当前函数,并伴有返回值,返回到函数的调用处
return; // 表示结束当前函数,直接会返回到函数调用处
多级调用
递归需要设置有效的出口条件,避免无穷递归
出口条件可能为多个
递归经典:斐波那契数列
TestFibonacci.java
数组
概念:一组连续的存储空间,存储多个相同数据类型的值
特点:类型相同,长度固定。
组成
数组中每个格子称为数组的元素
数组的下标从 0 开始,有效范围:0 ~ 数组长度-1
数组默认值:整数0, 小数0.0, 字符\u0000, 布尔false, 其他null
创建
①声明并分配空间
数据类型[] 变量名 = new 数据类型[数组大小值];
eg:
int[] arr = new int[5];
数据类型[] 变量名 = new 数据类型[数组大小值];
eg:
int[] arr = new int[5];
②先声明,再分配空间
数据类型[] 变量名;
变量名 = new 数据类型[数组大小值];
eg:
int[] arr;
arr = new int[5];
数据类型[] 变量名;
变量名 = new 数据类型[数组大小值];
eg:
int[] arr;
arr = new int[5];
③声明并赋值(繁)
数据类型[] 数组名 = new 数据类型[]{value1, value2, value3, ...};
eg:
int[] arr = new int[]{11, 22, 33, 44, 55, 66};
数据类型[] 数组名 = new 数据类型[]{value1, value2, value3, ...};
eg:
int[] arr = new int[]{11, 22, 33, 44, 55, 66};
④声明并赋值(简)
数据类型[] 数组名 = {value1, value2, value3, ...};
eg:
int[] arr = {11, 22, 33, 44, 55, 66};
数据类型[] 数组名 = {value1, value2, value3, ...};
eg:
int[] arr = {11, 22, 33, 44, 55, 66};
访问
数组名[下标];
eg:
int[2];
eg:
int[2];
长度
数组名.length
eg:
arr.length
eg:
arr.length
数组创建之后,长度不可变。
遍历
for (int i = 0; i < arr.length; i++) {
// arr[i] 使用数组元素
}
// arr[i] 使用数组元素
}
扩容
思路:创建一个新的更大的数组,将原数组内容复制到新数组中。
3种方式
循环将原数组内容逐一复制到新数组
System.arraycopy(原数组, 原数组起始, 新数组, 新数组起始, 长度);
java.util.Arrays.copyOf(原数组, 新长度); // 返回带有原数组值的新数组
数组变量中存储的是数组的首地址
返回值为数组类型,可直接赋值给原数组
【增删改查】
TestArrayAction.java
基本数据类型与引用数据类型
基本数据类型变量中存储的是 值
引用数据类型变量中存储的是 地址
排序
冒泡排序
相邻两个值比较大小(arr[j] > arr[j+1]),互换位置
记忆:外层0 ~ <length-1, 内层0 ~ <length-1-i
选择排序
固定值与其他值比较大小(arr[i] > arr[j]),互换位置
记忆:外层0 ~ <length-1, 内层i+1 ~ <length
JDK排序
java.util.Arrays.sort(数组名);
默认升序,降序需手工倒序
二维数组
概念:一维数组中的一维数组,数组中的元素还是数组
访问:数组名[高维下标][低维下标]
高维数组中的每一个元素,存储了低维数组的地址。
定义方式
* 先声明、再分配
数据类型[][] 数组名;
数组名 = new 数据类型[高维长度][低维长度];
数据类型[][] 数组名;
数组名 = new 数据类型[高维长度][低维长度];
* 声明并分配空间
数据类型[][] 数组名 = new 数据类型[高维长度][低维长度];
数据类型[][] 数组名 = new 数据类型[高维长度][低维长度];
* 声明并赋值(繁)
数据类型[][] 数组名 = new 数据类型[高维长度][]; //不规则数组
数组名[i] = new 数据类型[j]; //自行new低维属组
数据类型[][] 数组名 = new 数据类型[高维长度][]; //不规则数组
数组名[i] = new 数据类型[j]; //自行new低维属组
* 声明并赋值(简)
数据类型[][] 数组名 = {{v1, v2, v3}, {v4, v5, v6}, {...}}; //显示初始化
数据类型[][] 数组名 = {{v1, v2, v3}, {v4, v5, v6}, {...}}; //显示初始化
经典案例:杨辉三角
Demo
面向对象(OOP)
对象
万物皆对象。对象一定拥有自己的特征和行为。
特征:称之为属性,一般为名词,代表对象有什么。
行为:称之为方法,一般为动词,代表对象能做什么。
程序中的对象:来自于模板(类)创造出来程序中的实体(对象)
类与对象
类:定义了对象应具有的特征和行为,类是对象的模板
类的抽取:在一组相同或者类似的对象中,抽取共性的特征和行为。
对象:拥有多个特征和行为的实体,对象是类的实例
实例变量&局部变量
定义位置
局部变量:方法或方法内的结构中
实例变量:类的内部,方法的外部
默认值
局部变量:无默认值
实例变量:字面值(与数组相同0/null)
使用范围
局部变量:从定义行到其结构结束行
实例变量:本类有效
命名冲突
局部变量:不允许重名
实例变量:可与局部变量重名,局部变量优先
方法重载(Overload)
概念:一个类中定义多个相同名称的方法
到底采用哪种形式,需要取决于调用者给定的方法的参数。
要求
方法名称相同
参数列表不同(类型、个数、顺序)
与访问修饰符、返回值类型、形参的名称均无关
构造方法(Constructor)
概念:类中的特殊方法,主要用于创建对象
要求
名称与类名完全相同(包括大小写)
没有返回值类型修饰符(void也没有)
创建对象时触发构造方法的调用,不可通过.访问符访问
对象创建过程
内存堆区中开辟对象空间
为各个属性赋予初始值(默认0 / 0.0 / null)
执行构造方法中的代码
[将对象的地址赋值给变量]
注意
构造方法也可以重载,遵循重载规则
如果没有显示定义构造方法,编译器会默认提供一个无参构造方法
如果显示定义了有参构造方法,则无参构造方法必须也要显示定义
this关键字
概念:this是类中的默认引用,代表当前实例(当前对象)
语法
this.属性名 / this.函数名( )
this([参数列表])
三种用法
调用实例属性、实例方法,eg:this.name、this.sayHi()
调用本类中的其他构造方法,eg:this( )、this(实参)
this([实参])必须在构造方法的首行,仅可在构造方法中使用
表示当前方法(暂未用到)
三大特性
封装
概念:尽可能隐藏对象的内部实现细节,控制对象的修改和访问权限
访问修饰符: private 类型 属性;(可将属性全修饰为私有,仅本类可见)
get/set方法是外界访问对象私有属性的唯一通道,方法内部对属性检测和过滤
提供public公共访问方法,以保证数据可以正常录入和访问
继承
程序中的继承,是类与类之间特征和行为的一种赠予或获得。
类与类之间必须满足 is a 的关系。
父类的选择:功能越精细,重合点越多的,就越接近直接父类。
父类的抽象:
根据程序需要使用到的多个具体类,进行共性提取,进而定义父类。
在一组相同或类似的类中,抽取特征和行为,定义在父类中,实现重用。
根据程序需要使用到的多个具体类,进行共性提取,进而定义父类。
在一组相同或类似的类中,抽取特征和行为,定义在父类中,实现重用。
继承语法:class 子类名 extends 父类名{ } //定义子类时,显式定义父类
完整的子类:完整子类 = 父类共性 + 子类独有
Java为单继承,一个类只能有一个直接父类,但可以多级继承,属性和方法逐级叠加。
不可继承
构造方法:类中的构造方法,只负责创建本类对象,不可继承
private修饰的属性/方法:仅本类可见,不可继承
父子类不在同一个package中,且default修饰的属性和方法,不可继承
访问权限修饰符:
private/default/protected/public
private/default/protected/public
public 任何
protected 父子
default 同包
private 本类
跨包访问
写全限定名(包名.类名),eg: java.util.Arrays.copyOf(...);
导包(import),eg: import java.util.Arrays;
方法重写(Override)
同名:方法覆盖
当父类提供的方法无法满足子类的需求时,可在子类中定义和父类相同的方法进行覆盖(Override)
方法覆盖原则
方法名称、参数列表、返回值类型必须与父类相同;
访问修饰符应与父类相同或更宽泛;
执行机制:子类覆盖父类方法后,调用时优先执行子类覆盖后的方法
super关键字
用法1:子类去访问父类重名的属性/方法时(属性遮蔽、方法覆盖),使用super.专项访问父类的属性/方法
用法2:子类构造方法在调用父类构造方法时
super( ) 默认调用父类无参构造方法,隐式存在于构造方法的首行
super(参数) 指定调用父类有参构造方法,显式调用且编译器不在提供super( )执行
this与super
同一个子类构造方法中,super( )和this( )不可同时存在
当子类构造中使用了this()或this(实参),即不可再同时书写super()或super(实参),会由this()指向的构造方法完成super()的调用
继承关系下对象的创建
创建
继承关系下构建子类对象时,会先构建父类对象
由"父类共性" + "子类独有" 组合成一个完整的子类对象
流程
① 构建父类对象
② 初始化自身属性
③ 执行自身构造方法中的逻辑代码
多态
概念:父类引用指向子类对象,从而产生多种形态。eg: Animal a = new Dog();
二者具有直接或者间接的继承关系时,父类引用可指向子类对象,形成多态。
父类引用仅可调用父类所声明的属性和方法,父类不可调用子类独有的属性和方法。
多态场景下,如果子类覆盖过父类的方法,优先执行子类覆盖后的方法;否则执行父类的方法
多态的两种使用场景
父类引用作为方法的【形参】,实现多态,使方法参数的类型更为宽泛 (该父类任一子类均可作为实参传入)
父类引用作为方法【返回值】,实现多态,使方法可以可以返回不同的子类对象
向上转型(装箱)
概念:父类引用中保存真实子类对象。(多态核心概念)
eg: Animal a = new Dog(); // 对象层面的自动类型转换
调用:仅可调用父类中所声明的属性和方法(遵循属性遮蔽/方法覆盖原则)
向下转型(拆箱)
概念:将父类引用中的真实子类对象,强转回子类本身类型。
eg: Animal a = new Dog();
Dog dog = (Dog)a; // 对象层面的强制类型转换
Cat cat = (Cat)a; // Error: 不是真实子类对象new Dog(),编译OK,运行则会抛出类型转换异常:java.lang.ClassCastException
Dog dog = (Dog)a; // 对象层面的强制类型转换
调用:只有转回子类真实类型,才可调用子类独有的属性和方法。
向下转型前应该判断引用中的对象真实类型,保证类型转换的正确性。
语法: 父类引用 instanceof 子类类型 // 返回boolean类型结果,意为:父类包含子类对象真实类型,true包含,false不包含
三修饰符
abstract
修饰 类
概念:不够完整,不够具体,不能独立存在 的对象模型
语法:abstract class 类名 {}
作用
抽象类,不能直接独立new对象;
可被子类继承,提供共性属性和方法;
可声明为引用,强制使用多态(更纯粹的多态);
抽象类的构造方法作用:构建子类对象时,先构建父类对象(父类共性 + 子类独有 = 完整子类对象)
经验:abstract修饰后的抽象父类,依附于子类对象存在
修饰 方法
概念:抽象方法,不够完整、不够具体 的方法
语法:访问权限修饰符 abstract 返回值类型 函数名([参数列表]);
作用
只有方法声明,没有方法实现;
必须包含在抽象类中(abstract class XX{});
强制子类必须实现该方法,提供完整的、具体的调用版本;
总结
子类继承抽象类,子类必须覆盖父类中所有的抽象方法,否则子类还是抽象类;
抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类。
static
实例属性,是每个对象各自持有的独立内存空间(多份),对象单方面修改,不会影响其他对象。
静态属性,是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象。
Java中规定:不能将方法体内的局部变量声明为 static!
static 修饰的成员
静态属性 - 类属性
静态方法 - 类方法
不必创建对象,可直接通过类名访问【推荐】:类名.静态成员
静态方法规则
静态方法允许直接访问静态成员(不需要this.);
静态方法不允许直接访问非静态成员;
静态方法中不允许使用this或super关键字(构造方法可以);
静态方法可以继承,不能重写(覆盖)、没有多态;
静态代码块
在执行类时,希望先执行的初始化动作,
可以使用static定义一个静态代码区域,在类加载时即会被执行仅有的一次。
可以使用static定义一个静态代码区域,在类加载时即会被执行仅有的一次。
代码示例
类加载
JVM首次使用某个类时,需通过CLASSPATH查找该类的.class文件
将.class文件中对类的描述信息加载到内存中,进行保存
单独调用类加载语法:Class.forName("全限定名");
类加载时
触发:静态属性和静态代码块的执行 - (仅1次)
顺序:静态属性初始化之后执行静态代码块
作用:可谓静态属性赋值,或必要的初始化行为
final
概念:最后的,不可更改的。—— 保护类/方法/变量的功能和值
修饰内容
类(最终类)
此类不能被继承,eg:String, Math, System均为final修饰的类
方法(最终方法)
此方法不能被覆盖。
变量(最终变量)
此变量值不能被改变(常量 - 通常变量名全大写),eg: Math.PI
实例常量赋值
显式初始化、动态代码块、构造方法
要求
①DeadLine:在构造方法完成之前,为实例常量赋值即可;
②如果在构造方法中为实例常量赋值,必须保证所有的构造方法都能对其正确赋值。
静态常量赋值
显式初始化、静态代码块
要求
①Deadline:在类加载完成之前,为静态常量赋值即可。
对象常量赋值
final修饰基本类型:值不可变
final修饰引用类型:地址不可变
final作为形参使用
拷贝引用,为了避免引用值(地址)发生改变。
例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
接口【重要】
什么是接口
Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口用以扩容子类能力。
即:Java中使用抽象类/父类表示通用属性时,每个类只能继承一个类,假如子类已经从一个父类继承了,就不能再继续继承另外的父类。
但每个类可以实现多个接口,这样子类就拥有了更多的能力。
即:Java中使用抽象类/父类表示通用属性时,每个类只能继承一个类,假如子类已经从一个父类继承了,就不能再继续继承另外的父类。
但每个类可以实现多个接口,这样子类就拥有了更多的能力。
微观概念:接口是一种能力和约定。
接口的定义:代表了某种能力
方法的定义:能力的具体要求
宏观概念:接口是一种标准。
耦合度:模块与模块之间的关联程度。
关联的越密切,耦合越高;
关联的越松散,耦合越低。√
关联的越密切,耦合越高;
关联的越松散,耦合越低。√
接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。
接口的语法
定义
定义语法:interface 接口名 { }
public interface MyInterface {
public static final String FIELD = "value";
String S = "str"; // public static final 默认隐式存在、修饰
public abstract void method( );
void m( ); // public abstract 默认隐式存在、修饰
}
//public 关键字仅限用于接口在于其同名文件中被定义
public static final String FIELD = "value";
String S = "str"; // public static final 默认隐式存在、修饰
public abstract void method( );
void m( ); // public abstract 默认隐式存在、修饰
}
//public 关键字仅限用于接口在于其同名文件中被定义
定义要求:
没有构造方法,不能创建对象
只能定义:公开静态常量、公开抽象方法、公开静态方法(jdk1.8新特性-可有方法体,接口名直接调用)
使用
使用语法:implements 接口名,接口名,...
// 增加/赋予1种/多种能力(逗号分隔) [约定]
calss Sub extends Super implements 接口名,接口名 {
@OverRide
public 返回值 method( ) { ... }
@OverRide
public void m( ) { ... }
}
calss Sub extends Super implements 接口名,接口名 {
@OverRide
public 返回值 method( ) { ... }
@OverRide
public void m( ) { ... }
}
使用规范:
任何类在实现接口时,必须实现接口中所有抽象方法,否则此类为抽象类
实现接口中的抽象方法,访问修饰符必须是public
对比抽象类
相同
1.可编译为字节码文件(.class)
2.不能创建对象(接口不是类,也没有构造方法)
3.可以作为引用类型
4.具备Object类中所定义的方法
2.不能创建对象(接口不是类,也没有构造方法)
3.可以作为引用类型
4.具备Object类中所定义的方法
不同
1.所有属性都只能且默认是公开静态常量,隐式使用public static final修饰
2.所有方法都只能且默认是公开抽象方法,隐式使用public abstract修饰
3.没有构造方法、没有动态/静态代码块
2.所有方法都只能且默认是公开抽象方法,隐式使用public abstract修饰
3.没有构造方法、没有动态/静态代码块
接口引用【重要】
同父类一样,接口也可声明为引用,并指向真实类对象。
【注意】
使用接口引用作为方法形参,实现更自然的多态(只关注能力-具备能力的类对象均可传入)
仅可调用接口中所声明的方法,不可调用实现类中独有的方法
可强转回真实类本身类型,进行独有方法调用(注意判断真实类对象 instanceof)
常见关系
类与类:单继承,extends 父类名称
类与接口:多实现,implements 接口名1,接口名2,接口名3
接口与接口:多继承,extends 父接口1,父接口2,父接口3
常量接口
将多个常用于表示状态或者固定值的变量,以静态常量的形式定义在接口中同一管理,提高代码可读性。
常量接口使用语法:接口名.常量名
常量接口示例代码
接口回调【重要】
思路顺序:
(1)接口/标准
(2)接口使用者
(3)接口实现者
(1)接口/标准
(2)接口使用者
(3)接口实现者
重在理解、应用。
先有接口的使用者,后有接口的实现者。
对象数组排序
对象数组排序使用Java已知的接口/标准
intreface Comparable { ... }
接口使用者,在工具类中成员方法传参形式调用(接口回调)
java.util.Arrays.sort(对象数组);
接口实现者,在实现类中编写对应覆盖方法逻辑(方法覆盖)
class 类名 implements Comparable<类名> {
@Override
public int compareTo(类名 o) { /* 参考JDK文档 */ }
}
@Override
public int compareTo(类名 o) { /* 参考JDK文档 */ }
}
测试类 main( ) 中调用测试验证
常类方法
内部类
内部类
概念:在一个类的内部再定义一个完整的类。
语法:
class Outer {
class Inner {
}
}
class Inner {
}
}
编译:Outer$Inner.class 和 Outer.class
特点:
* 编译之后可生成独立的字节码文件
* 内部类可直接访问外部类的私有成员,而不破坏封装
* 可为外部类提供必要的内部功能组件
* 内部类可直接访问外部类的私有成员,而不破坏封装
* 可为外部类提供必要的内部功能组件
成员内部类
概念:
在类的内部定义,与实例变量、实例方法同级别的类。
属于外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象
在类的内部定义,与实例变量、实例方法同级别的类。
属于外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象
语法:
// 定义语法同 内部类
// 创建内部类对象
Outer out = new Outer();
Inner in = out.new Inner(); // 特殊:不具普适性
// 成员内部类访问外部类的重名属性
Outer.this.属性名
// 创建内部类对象
Outer out = new Outer();
Inner in = out.new Inner(); // 特殊:不具普适性
// 成员内部类访问外部类的重名属性
Outer.this.属性名
特点:
* 当外部类、内部类存在重名属性时,会优先访问内部类属性。
* 成员内部类不能定义静态成员
* 成员内部类不能定义静态成员
静态内部类
概念:不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员
语法:
static 内部类 { }
特点:
* 只能直接访问外部类的静态成员(势力成员需实例化外部类对象)
局部内部类
概念:定义在外部类的成员方法中,作用范围和创建对象范围仅限于当前方法
语法:
class Outer {
public void m( ) {
class Inner {
}
}
}
public void m( ) {
class Inner {
}
}
}
特点:
* 不能有静态成员(属性/方法)
* 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final
* 隐藏类的信息,限制类的使用范围
* 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final
* 隐藏类的信息,限制类的使用范围
匿名内部类
概念:没有类名的局部内部类(一切特征都与局部内部类相同)
语法:
class Outer {
public OutInterface m ( ) {
return new OutInterface( ) { // 匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
}
public OutInterface m ( ) {
return new OutInterface( ) { // 匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
}
特点:
* 必须继承一个父类或者实现一个接口
* 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
* 使用场景:① 显式继承父类时 ② 实现接口时
* 优点:可以减少代码量,书写的思路流畅
* 缺点:可读性较差
* 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
* 使用场景:① 显式继承父类时 ② 实现接口时
* 优点:可以减少代码量,书写的思路流畅
* 缺点:可读性较差
包装类
* 基本数据类型所对应的引用数据类型(8种)。
* Object可统一所有数据,包装类的默认值是null。
* 包装类中实际上就是持有了一个基本类型的数据,作为数据的存储空间(Byte中有一个byte的value属性),还提供了常用的转型方法,以及常量。既可以存储值,又具备了一系列功能。
* 包装类型中提供了若干转型的方法,可以让自身类型与其他包装类型、基本类型、字符串相互之间进行转换。
* Object可统一所有数据,包装类的默认值是null。
* 包装类中实际上就是持有了一个基本类型的数据,作为数据的存储空间(Byte中有一个byte的value属性),还提供了常用的转型方法,以及常量。既可以存储值,又具备了一系列功能。
* 包装类型中提供了若干转型的方法,可以让自身类型与其他包装类型、基本类型、字符串相互之间进行转换。
8种包装类:Byte / Short / Integer / Long / Float / Double / Boolean / Character
转型方法
① xxxValue( )
成员转型方法,java.lang.Number 父类为所有子类分别提供了6种对应类型互相转型的方法,将自身类型转换成其他数字型;
成员转型方法,java.lang.Number 父类为所有子类分别提供了6种对应类型互相转型的方法,将自身类型转换成其他数字型;
② parseXxxx(String s)
静态转型方法,服务7种包装类型(除了Character包装类型都可以通过String构建);
静态转型方法,服务7种包装类型(除了Character包装类型都可以通过String构建);
③ valueOf(基本类型)、valueOf(字符串类型)
静态转型方法,服务8种包装类型;
静态转型方法,服务8种包装类型;
④ JDK5之后,赋值时提供自动装箱、拆箱:
Byte b4 = 40; // 【自动装箱】将基本类型直接赋值给包装类型,调用valueOf(short s)
byte b5 = b4; // 【自动拆箱】将包装类型引用赋值给基本类型(赋的是值),调用byteValue()返回基本类型
Byte b4 = 40; // 【自动装箱】将基本类型直接赋值给包装类型,调用valueOf(short s)
byte b5 = b4; // 【自动拆箱】将包装类型引用赋值给基本类型(赋的是值),调用byteValue()返回基本类型
⑤ Java预先创建了256个常用的整数包装类型对象(-128~127的常数),在实际应用当中,对已创建的对象进行复用,节约内存效果明显。
【注意】使用字符串构建包装类型对象时,要保证类型的兼容,否则产生 NumberFormatException 异常。
Object类
简介:超类、基类,所有类的直接或间接父类,位于继承树的最高层
特点:
* 任何类,如果没有书写extends显式继承某个类,都默认继承Object类
* Object类中所定义的方法,是所有对象都具备的方法
* Object类可以存储任何对象:作为参数,可接收任何对象;作为返回值,可返回任何对象。
* Object类中所定义的方法,是所有对象都具备的方法
* Object类可以存储任何对象:作为参数,可接收任何对象;作为返回值,可返回任何对象。
方法:
getClass().getName()
返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
toString()
返回该对象的字符串表示(表现形式)。
可以根据程序需求覆盖该方法,如展示对象各个属性值。
特点:
* 对象中属性的表现形式,常用于展示对象的各个属性。
可以根据程序需求覆盖该方法,如展示对象各个属性值。
特点:
* 对象中属性的表现形式,常用于展示对象的各个属性。
hashCode()
返回该对象的十六进制的哈希码值(对象在内存中的数字型名字)。
哈希算法根据对象的地址或者字符串或者数字计算出来的int类型的数值。
哈希码并不唯一,可保证相同对象返回相同的哈希码,尽量保证不同对象返回不同的哈希码值。
哈希算法根据对象的地址或者字符串或者数字计算出来的int类型的数值。
哈希码并不唯一,可保证相同对象返回相同的哈希码,尽量保证不同对象返回不同的哈希码值。
equals()
默认实现为 this == obj, 比较两个地址是否相同。
特点:
* 可进行覆盖,比较两个对象的内容是否相同。
特点:
* 可进行覆盖,比较两个对象的内容是否相同。
重写覆盖父类Object.equals()方法五步走
判断引用地址是否相同
判断引用地址是否为空
确认对象类型是否一致
转型 - 向下转型拆箱
比较对象中的实际内容
基本数据类型:==
字符串类型:str1.equals(str2)
finalize()
protected void finalize() throws Throwable { }
当对象被判定为辣鸡对象时,由JVM自动调用此方法,用以标记辣鸡对象,进入回收队列。
辣鸡对象:没有有效引用只想此对象时,为辣鸡对象。
垃圾回收:由GC销毁辣鸡对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有辣鸡对象。
手动回收机制:使用System.gc( );通知JVM触发垃圾回收。
辣鸡对象:没有有效引用只想此对象时,为辣鸡对象。
垃圾回收:由GC销毁辣鸡对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有辣鸡对象。
手动回收机制:使用System.gc( );通知JVM触发垃圾回收。
面试题:final finalize finally
* final 修饰词,类不可继承/方法不可覆盖/基本类型值不能修改/引用类型地址不可修改
* finalize 方法,JVM自动调用,标记辣鸡对象进入回收队列;手动调用,使用System.gc()方法触发
* finally 关键字,作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。
* final 修饰词,类不可继承/方法不可覆盖/基本类型值不能修改/引用类型地址不可修改
* finalize 方法,JVM自动调用,标记辣鸡对象进入回收队列;手动调用,使用System.gc()方法触发
* finally 关键字,作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。
wait(),wait(long),wait(long,int),notify(),notifyAll()
String类
特点
* 字符串是常量,创建后不可改变;
* 字符串字面值存储在字符串池中,可以共享;
* 字符串字面值存储在字符串池中,可以共享;
创建
String s = "Hello"; // 产生1个对象,字符串池中存储(方法区常量池中字符串池)
String s = new String("Hello"); // 产生2个对象,堆、方法区常量池中各存储一个
String s = new String("Hello"); // 产生2个对象,堆、方法区常量池中各存储一个
方法
1.根据下标获取字符
s.charAt(0);
2.判断是否包含子字符串
s.contains("llo");
3.将字符串转换为数组
s.toCharArray();
4. 查找子字符串在字符串中第一次出现的位置,不存在返回-1
s.indexOf("o");
5. 查找子字符串在字符串中最后一次出现的索引,不存在返回-1
s.lastIndexOf("ld");
6. 判断字符串是否为空
str.isEmpty()
7. 返回字符串长度
s.length()
8. 去掉字符串前后空格
s2.trim()
9. 大小写转换 - 返回字符串副本,不会修改原字符串
hi.toUpperCase();
hi.toLowerCase();
10. 忽略大小写比较
upper.equals(lower) // 字符串完全一样返回true,否则false
upper.equalsIgnoreCase(lower)
11. 判断是否以某个字符串结尾
filename.endsWith(".java");
12. 替换字符串中的字符 - 返回字符串副本,不会修改源字符串
s.replace('o', 'O');
s.replace("Hello", "GoodBye");
13. 字符串分割,返回字符串数组
text.split(",");
14. 从指定下标位置到结尾,获取子字符串,通常嵌套使用
text.substring(8);
可变长字符串
StringBuilder
可变长字符串,JDK5.0提供,运行效率快、线程不安全。
StringBuffer
可变长字符串,JDK1.0提供,运行效率慢、线程安全。
BigDecimal类
位置:java.math包中
作用:精确计算浮点数
创建:BigDecimal bd = new BigDecimal("1.0");
作用:精确计算浮点数
创建:BigDecimal bd = new BigDecimal("1.0");
方法
BigDecimal add(BigDecimal db) //加
BigDecimal subtract(BigDecimal bd)//减
BigDecimal multiply(BigDecimal bd)//乘
BigDecimal divide(BigDecimal db) //除
BigDecimal subtract(BigDecimal bd)//减
BigDecimal multiply(BigDecimal bd)//乘
BigDecimal divide(BigDecimal db) //除
【注意】
除法:BigDecimal(BigDecimal bd, int scal, RoundingMode mode)
@scal, 指定精确到的小数位数
@mode, 指定小数部分的取舍模式,通常采用四舍五入模式(BigDecimal.ROUND_HALF_UP)
@scal, 指定精确到的小数位数
@mode, 指定小数部分的取舍模式,通常采用四舍五入模式(BigDecimal.ROUND_HALF_UP)
集合框架
集合
概念:对象的容器,存储对象的对象,绝大多数情况下可替代数组。
特点:容器的工具类,定义了多个对象进行操作的常用方法。
位置:java.util.*
泛型集合与工具类
泛型集合及用法
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点
1. 编译时即可检查,而非运行时抛出异常;
2. 访问时,不必类型转换(拆箱);
3. 不同泛型之间引用不能相互赋值,泛型不存在多态。
2. 访问时,不必类型转换(拆箱);
3. 不同泛型之间引用不能相互赋值,泛型不存在多态。
高级
<T>
* <T> 代表某种通配类型,还有诸如<E><K,V>等
* <T extends Object> 约定类型T为Object的子类
* <T extends MyClass> 约定类型T只能为MyClass类的子类
* <T extends MyClass & MyInterFace> 约定类型T为MyClass子类同时实现了MyInterFace接口,父类必须写在最前面且可&上多个接口
* <T extends MyInterFace> 约定类型T只要实现了MyInterface接口
* <T extends MyInterFace<T>> 约定类型T要实现了MyInterface接口(且必须为T泛型的接口)
* <T extends Object> 约定类型T为Object的子类
* <T extends MyClass> 约定类型T只能为MyClass类的子类
* <T extends MyClass & MyInterFace> 约定类型T为MyClass子类同时实现了MyInterFace接口,父类必须写在最前面且可&上多个接口
* <T extends MyInterFace> 约定类型T只要实现了MyInterface接口
* <T extends MyInterFace<T>> 约定类型T要实现了MyInterface接口(且必须为T泛型的接口)
<?>
* <?> 代表任意通配泛型
* <? extends FatherClass> 泛型类型?必须是FatherClass的子类
* <? extends MyInterface> 泛型类型?必须是MyInterface的实现类
* <? super SubClass> 泛型类型?必须是SubClass类或SubClass的父类
* <? extends MyInterface<? extends T>> 泛型类型?必须是MyInterface的实现类,且接口又指定了泛型(必须T类型的子类)
* <T extends MyInterface<? super T>> 要求T所代表的类型必须实现MyInterface接口,同时,接口泛型必须是T类型或T的父类
* <? extends FatherClass> 泛型类型?必须是FatherClass的子类
* <? extends MyInterface> 泛型类型?必须是MyInterface的实现类
* <? super SubClass> 泛型类型?必须是SubClass类或SubClass的父类
* <? extends MyInterface<? extends T>> 泛型类型?必须是MyInterface的实现类,且接口又指定了泛型(必须T类型的子类)
* <T extends MyInterface<? super T>> 要求T所代表的类型必须实现MyInterface接口,同时,接口泛型必须是T类型或T的父类
普通泛型
* 类:创建对象时,为类所定义的泛型,进行参数化赋值
* 接口:实现接口时,为接口所定义的泛型,进行参数化赋值
* 接口:实现接口时,为接口所定义的泛型,进行参数化赋值
静态泛型
* 定义在方法的返回值类型前:<T>/<T extends Object>/<T extends Comparable<T>>/<T extends Comparable<? super T>>,可使用&多接口
* 定义在方法的形参列表当中:<?>/<? extends Object>/<? super SubClass>,不可使用&
* 定义在方法的形参列表当中:<?>/<? extends Object>/<? super SubClass>,不可使用&
Collections工具类
概念:集合工具类,定义了除了存储以外的集合常用方法。
方法
public static void sort(List<?> list) // 排序,要求:必须实现Comparable接口,必须可与自身类型比,以及父类类型比
public static void reverse(List<?> list) // 反转,倒置元素
public static void shuffle(List<?> list) // 随机重置顺序(洗牌)
public static void reverse(List<?> list) // 反转,倒置元素
public static void shuffle(List<?> list) // 随机重置顺序(洗牌)
Collection体系集合
概念:代表该体系结构的根接口,代表一组对象,称为“集合”;每个对象都是该集合的“元素”
特点:代表一组任意类型的对象,无序、无下标。(Collection为父接口)
方法:参考jdk1.8-API文档
boolean add(Object obj) // 添加一个对象
boolean addAll(Collection c) // 将一个集合中的所有对象添加到此集合中
void clear() // 清空此集合中的所有对象
boolean contains(Object o) // 检查次集合中是否包含o对象
boolean equals(Object o) // 比较此集合是否指定对象相等
boolean isEmpty() // 判断此集合是否为空
boolean remove(Object o) // 在此集合中移除o对象
int size() // 返回此集合中的元素个数
Object[] toArray() // 将此集合转换成数组
boolean addAll(Collection c) // 将一个集合中的所有对象添加到此集合中
void clear() // 清空此集合中的所有对象
boolean contains(Object o) // 检查次集合中是否包含o对象
boolean equals(Object o) // 比较此集合是否指定对象相等
boolean isEmpty() // 判断此集合是否为空
boolean remove(Object o) // 在此集合中移除o对象
int size() // 返回此集合中的元素个数
Object[] toArray() // 将此集合转换成数组
List接口与实现类
继承:父接口Collection
特点:有序、有下标、元素可重复
方法:继承了父接口Collection提供的共性方法,同时定义了一些独有的与下标相关的操作方法
实现类
ArrayList类(数组)【重点】
特点:
1. 数组结构实现,查询快、增删慢;
2. JDK1.2版本,运行效率快、线程不安全;
1. 数组结构实现,查询快、增删慢;
2. JDK1.2版本,运行效率快、线程不安全;
场景:注册(1次) -> 查询(n次)
注意:
* JDK7之前,无参构造方法实际创建长度为 10 的Object数组,用还是不用,数组就在那里,爱用不用(占了内存)
* JDK8之后,无参构造方法实际创建长度为 0 的Object数组,首次add元素时,才执行数组扩容操作,然后真正向数组中插入数据(Lazy懒),用的时候创建或加载,有效降低无用内存的占用。
* JDK7之前,无参构造方法实际创建长度为 10 的Object数组,用还是不用,数组就在那里,爱用不用(占了内存)
* JDK8之后,无参构造方法实际创建长度为 0 的Object数组,首次add元素时,才执行数组扩容操作,然后真正向数组中插入数据(Lazy懒),用的时候创建或加载,有效降低无用内存的占用。
方法:参考jdk1.8-API文档
Vector类(数组、线程同步)
特点:
1. 数组结构实现,查询快、增删慢;
2. JDK1.0版本,运行效率慢、线程安全。
1. 数组结构实现,查询快、增删慢;
2. JDK1.0版本,运行效率慢、线程安全。
方法:参考jdk1.8-API文档
LinkedList类(链表)
特点:
1. 链表结构实现,增删快,查询慢;
1. 链表结构实现,增删快,查询慢;
对比
ArrayList:必须开辟连续空间,查询快,增删慢。运行快,线程不安全。
Vector:必须开辟连续空间,查询快,增删慢。运行慢,线程安全。
LinkedList:无需开辟连续空间,查询慢,增删快。
Vector:必须开辟连续空间,查询快,增删慢。运行慢,线程安全。
LinkedList:无需开辟连续空间,查询慢,增删快。
Set接口与实现类
继承:父接口Collection
特点
1)无序、无下标、元素不可重复(当插入新元素时,如果新元素与已有元素进行equals比较,结果为true时,则拒绝新元素插入)
2)set接口并没有提供自己独有的方法,均是继承Collection的方法
2)set接口并没有提供自己独有的方法,均是继承Collection的方法
去重逻辑
hashCode( )比较
不同:对象一定不同(add成功)
相同:对象不一定不同
this==o地址比较
true:对象一定相同(add失败)
false:equals( )内容比较
true:内容相同(add失败)
false:内容不同(add成功)
实现类
HashSet类(HashCode-无序不重复)【重点】
特点:
* 基于HashCode实现元素不重复 - 无序
* 当存入元素的哈希码相同时,会调用equals确认,结果为true,则拒绝后者加入
* 无参构建初始容量为16(负载因子0.75,即+75%容量扩容)
* 底层使用的HashMap类,即将所有需要存储的值,通过HashMap去重存入
* 先判断hashCode是否相同,再==比较地址是否相同,再equals内容是否相同
* 基于HashCode实现元素不重复 - 无序
* 当存入元素的哈希码相同时,会调用equals确认,结果为true,则拒绝后者加入
* 无参构建初始容量为16(负载因子0.75,即+75%容量扩容)
* 底层使用的HashMap类,即将所有需要存储的值,通过HashMap去重存入
* 先判断hashCode是否相同,再==比较地址是否相同,再equals内容是否相同
LinkedHashSet类(记录插入顺序)
特点:
* 继承自HashSet,又基于LinkedHashMap来实现的
* 底层使用LinkedHashMap(链表结构)存储,节点形式独立存储数据,
并可以指向下一个节点,通过顺序访问节点,可保留元素的插入顺序 - 插入顺序
* 所有方法与HashSet相同,用法也一模一样
* 继承自HashSet,又基于LinkedHashMap来实现的
* 底层使用LinkedHashMap(链表结构)存储,节点形式独立存储数据,
并可以指向下一个节点,通过顺序访问节点,可保留元素的插入顺序 - 插入顺序
* 所有方法与HashSet相同,用法也一模一样
TreeSet类(二叉树-自动排序)
特点:
* 基于排列顺序实现元素不重复 - 自动排序
* 实现了SortedSet接口,对所有插入集合的元素自动排序
* 元素对象的类型必须实现Comparable接口,指定排序规则(Integer/String类默认实现),
通过重写CompareTo方法才能使用,以确定是否为重复元素
* 基于排列顺序实现元素不重复 - 自动排序
* 实现了SortedSet接口,对所有插入集合的元素自动排序
* 元素对象的类型必须实现Comparable接口,指定排序规则(Integer/String类默认实现),
通过重写CompareTo方法才能使用,以确定是否为重复元素
排序
方式一:遍历加入到List中使用Collections.sort(list)排序;
方式二:使用TreeSet的构造创建一个TreeSet对象实现自动排序;
Map接口与实现类
特点
* 用于存储任意键值对(Key:Value)
* 键:无序、无下标、不允许重复(唯一)
* 值:无序、无下标、允许重复
* 键:无序、无下标、不允许重复(唯一)
* 值:无序、无下标、允许重复
接口方法
* V put(K key, V value) // 将对象存入集合中,关联键值,key重复则覆盖value
* Object get(Object key) // 根据键获取对应的值
* Set<K> // 返回所有key
* Collection<V> values() // 返回包含所有值的Collection集合
* Set<Map.Entry<K,V>> // 键值匹配的Set集合
* Object get(Object key) // 根据键获取对应的值
* Set<K> // 返回所有key
* Collection<V> values() // 返回包含所有值的Collection集合
* Set<Map.Entry<K,V>> // 键值匹配的Set集合
子接口
SortedMap接口
实现类
HashMap类(效率快+允许null)重点
特点:
* JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value
* 无参构建初始容量为16(负载因子0.75,即+75%容量扩容)
* HashMap算法:拿到任何一个对象后,通过hash(key)做运算,key>>>16(除16),只可能得到0-15之间的一个数组,作为插入数组的下标。
* JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value
* 无参构建初始容量为16(负载因子0.75,即+75%容量扩容)
* HashMap算法:拿到任何一个对象后,通过hash(key)做运算,key>>>16(除16),只可能得到0-15之间的一个数组,作为插入数组的下标。
LinkedHashMap类(记录插入顺序)
特点:HashMap的一个子类,保存了记录的插入顺序,也可在构造时带参数,按照访问次序排序。
Hashtable类(线程安全)
特点:JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value
Properties类(配置文件读取)
特点:Hashtable的子类,要求key和value都是String,通常用于配置文件的读取。
Demo
TreeMap类(自动排序)
特点:实现了SortedMap接口(Map的子接口),可以对key自动排序。
foreach循环
for (数据类型 变量名 : 容器名称) {
//可遍历集合或数组(常用在无序集合上)
}
//可遍历集合或数组(常用在无序集合上)
}
异常处理
异常的概念
概念:程序在运行过程中出现的特殊情况
必要性:任何程序都可能存在大量的位置问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
必要性:任何程序都可能存在大量的位置问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
异常的分类
位置:java.lang.Throwable;
Throwable类
Error类(不可处理)
Exception类
RuntimeException类
CheckedException类
除了RuntimeException类与其子类,以及错误Error类,其他的都是检查异常。
异常的产生
自动
当程序运行时遇到不符合规范的代码或结果时,会产生异常;
手动
throw new 异常类型("实际参数");
1.创建异常对象
2.结合throw关键字,抛出异常
用在【方法内】
异常的传递
概念:按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)
* 受查异常:throws 声明对应的方法可能存在异常,声明修饰在方法参数列表后端【方法上】,可以用","分隔指定声明多个异常
* 运行时异常:因可处理可不处理,无需声明异常
* 运行时异常:因可处理可不处理,无需声明异常
异常的处理
try {
// 可能出现异常的代码
} catch (Exception e) {
// 异常处理的相关代码(三种方案)
// 方案1:自定义处理, 如println();
// 方案2:打印堆栈跟踪信息, e.printStackTrace();
// 方案3:获取异常的原因信息, println(e.getMessage());
[... 多重 catch () ...] // 遵循从子到父的顺序,父类异常在最后。
} finally {
// 无论是否出现异常都会执行的代码结构(不受return影响),常用于释放资源
}
// 可能出现异常的代码
} catch (Exception e) {
// 异常处理的相关代码(三种方案)
// 方案1:自定义处理, 如println();
// 方案2:打印堆栈跟踪信息, e.printStackTrace();
// 方案3:获取异常的原因信息, println(e.getMessage());
[... 多重 catch () ...] // 遵循从子到父的顺序,父类异常在最后。
} finally {
// 无论是否出现异常都会执行的代码结构(不受return影响),常用于释放资源
}
try-catch
try-catch-catch
try-catch-finally
try-catch-catch-...-finally
try-finally(不常见)
try-catch-catch
try-catch-finally
try-catch-catch-...-finally
try-finally(不常见)
自定义异常
定义
必须继承自Exception或Exception的子类,常用RuntimeException
必须提供无参构造方法;
必须提供String message的1参构造方法,super(message);
抛出
Exception受查异常
声明:①需要声明该异常,传递出去; ②声明的异常类型与抛出的异常类型一致
抛出:throw new 自定义异常类名(异常提示字符串);
RuntimeException运行时异常
声明:可声明/可不声明
抛出:throw new 自定义异常类名(异常提示字符串);
打印突出显示的错误信息(serr)
System.err.println(e.getMessage());
异常方法覆盖
* 0. 方法名、参数列表、返回值类型必须和父类相同(覆盖的基本要求)
* 1. 父类中方法没有声明异常,则子类中也不可以声明异常
* 2. 父类中方法声明了异常,子类重写后可声明也可不声明,如果声明则必须是与其相同或其异常子类
* 3. 子类可以声明比父类更多的异常,但必须小于父类的异常类(即异常子类) - 即子类不能抛出比父类更多、更宽的异常
* 1. 父类中方法没有声明异常,则子类中也不可以声明异常
* 2. 父类中方法声明了异常,子类重写后可声明也可不声明,如果声明则必须是与其相同或其异常子类
* 3. 子类可以声明比父类更多的异常,但必须小于父类的异常类(即异常子类) - 即子类不能抛出比父类更多、更宽的异常
多线程
线程概念
进程:程序静止的,真正运行时的程序,才被称为进程。(宏观并行,微观串行)
线程:轻量级进程(Light Weight Process),程序中的一个顺序控制流程,同时也是CPU的基本调度单位,
进程由1个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。
线程:轻量级进程(Light Weight Process),程序中的一个顺序控制流程,同时也是CPU的基本调度单位,
进程由1个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。
eg
迅雷,是一个进程,当中的多个不同的下载任务即多个线程。
JVM,Java虚拟机是一个进程(单进程),当中默认包含主线程(main),可通过代码创建多个独立线程,与main并发执行。
JVM,Java虚拟机是一个进程(单进程),当中默认包含主线程(main),可通过代码创建多个独立线程,与main并发执行。
扩展
获取win电脑当前CPU核心数命令:
① win+R ② wmic ③ cpu get NumberOfCores
① win+R ② wmic ③ cpu get NumberOfCores
线程组成
① CPU时间片
操作系统会为每个线程分配执行时间
② 运行数据
* 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象;
* 栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈;
* 栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈;
③ 线程逻辑代码
线程创建
继承父类
步骤
① 继承Thread类
② 覆盖run()方法
③ 创建子类对象
④ 调用start()方法 - 启动线程
② 覆盖run()方法
③ 创建子类对象
④ 调用start()方法 - 启动线程
示例
MyThread t1 = new MyThread();
t1.start();
t1.start();
实现接口【推荐】
步骤
① 实现Runnable接口
② 覆盖run()方法
③ 创建实现类对象
④ 创建线程对象(Thread父类有参构造)
⑤ 调用start()方法 - 启动线程
② 覆盖run()方法
③ 创建实现类对象
④ 创建线程对象(Thread父类有参构造)
⑤ 调用start()方法 - 启动线程
示例
Thread t2 = new Thread(new MyRunnable());
t1.start();
t1.start();
特点
* 只是将当前类变成线程任务类,本身不是个线程
* run任务是可以多线程对象共享(任务复用)
* 更灵活(还可以继承其他的类 + 实现其他的接口能力)
* run任务是可以多线程对象共享(任务复用)
* 更灵活(还可以继承其他的类 + 实现其他的接口能力)
并发计算
Callable接口
public interface Callable<V> {
public V call() throws Exception;
}
public V call() throws Exception;
}
* JDK5加入,与Runnable接口类似,实现之后代表一个线程任务;
* Callable具有泛型返回值,可以声明异常。
* Callable具有泛型返回值,可以声明异常。
Future接口
public interface Future<V>
* 异步接收ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值;
* 成员方法:
V get()以阻塞形式等待Future中的异步处理结果(call()的返回值), 该方法会抛出InterruptedException, ExecutionException异常
* 成员方法:
V get()以阻塞形式等待Future中的异步处理结果(call()的返回值), 该方法会抛出InterruptedException, ExecutionException异常
线程状态(6)
初始New → 运行RUNNABLE → 等待WAITING(限期/无限期) → 阻塞BLOCKED → 终止TERMINATED
* JDK5之后,READY+RUNNING = RUNNABLE(运行态)
所有线程状态图示
线程方法
基本
Thread.currentThread().getId() // 返回当前线程标识符(线程ID)
Thread.currentThread().getName() // 返回当前线程对象名(线程名)
休眠
public static void sleep(long millis)
// 当前线程主动休眠millis毫秒
// 当前线程主动休眠millis毫秒
特点
* 静态方法,直接类名调用Thread.sleep(1000);
* 使当前线程进入阻塞状态,在指定时间内不会执行,不推荐使用;
* sleep()被调用时该线程不会释放它所拥有的锁;
* 该方法会抛出InterruptedException中断异常;
* 使当前线程进入阻塞状态,在指定时间内不会执行,不推荐使用;
* sleep()被调用时该线程不会释放它所拥有的锁;
* 该方法会抛出InterruptedException中断异常;
放弃
public static void yield( )
// 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
// 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
特点
* 静态方法,直接类名调用Thread.yield();
* yield只是使当前线程重新回到就绪状态,所以执行yield的线程有可能在进入到就绪状态后马上又被执行。
yield只能使同优先级或更高优先级的线程有执行的机会。
* 可能对调试或测试有用,可能有助于根据竞态条件重现错误。
在设计并发控制结构(例如java.util.concurrent.locks包中的并行控制结构)时也可能有用。
* yield只是使当前线程重新回到就绪状态,所以执行yield的线程有可能在进入到就绪状态后马上又被执行。
yield只能使同优先级或更高优先级的线程有执行的机会。
* 可能对调试或测试有用,可能有助于根据竞态条件重现错误。
在设计并发控制结构(例如java.util.concurrent.locks包中的并行控制结构)时也可能有用。
结合
public final void join( )
// 允许其他的线程加入到当前线程中来(插队),等待join的线程终止
// 允许其他的线程加入到当前线程中来(插队),等待join的线程终止
特点
* 成员方法/最终方法,不能被覆盖;
* 如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复;
* 能够释放当前线程锁,其他线程可以调用次线程中的同步方法;
* 该方法会抛出InterruptedException中断异常;
* 如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复;
* 能够释放当前线程锁,其他线程可以调用次线程中的同步方法;
* 该方法会抛出InterruptedException中断异常;
线程同步
线程为什么不安全?
当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致;
* 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可以保证正确性;
* 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省;
* 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可以保证正确性;
* 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省;
同步方式
方式:同步代码块
synchronized (临界资源对象) { // 对临界资源加锁
//代码(原子操作)
}
//代码(原子操作)
}
注意
* 每个对象都有一个互斥锁标记,用来分配给线程的;
* 只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块;
* 线程退出同步代码块时,会释放相应的互斥锁标记;
* 只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块;
* 线程退出同步代码块时,会释放相应的互斥锁标记;
方式:同步方法
synchronized 返回值类型 方法名称(形参列表) { // 对当前对象(this)加锁
// 代码(原子操作)
}
// 代码(原子操作)
}
注意
* 只有拥有对象互斥锁标记(eg:Object lock;)的线程,才能进入该对象加锁的同步方法中;
* 线程退出同步方法时,会释放相应的互斥锁标记。
* 线程退出同步方法时,会释放相应的互斥锁标记。
同步规则
只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记
如果在调用不包含同步代码块的方法,或普通方法时,则不需要锁标记,可直接调用
已知线程安全的类
① StringBuilder
② Vector
③ Hashtable
② Vector
③ Hashtable
公开成员方法均为synchronized修饰的同步方法。
线程通信
阻塞/等待
Object类的成员方法:
public final void wait()
public final void wait(long timeout)
public final void wait()
public final void wait(long timeout)
说明:必须在对共享临界资源(obj)加锁的同步代码块/同步方法中。
在一个线程中调用obj.wait()时,此线程会释放其拥有的所有锁标记,同时此线程阻塞在obj的等待队列中。
即当前线程释放锁,进入等待队列(无限期等待 - 除非收到通知)。
在一个线程中调用obj.wait()时,此线程会释放其拥有的所有锁标记,同时此线程阻塞在obj的等待队列中。
即当前线程释放锁,进入等待队列(无限期等待 - 除非收到通知)。
通知/唤醒
Object类的成员方法:
public final void notify()
public final void notifyAll()
public final void notify()
public final void notifyAll()
说明:必须在对共享临界资源(obj)加锁的同步代码块/同步方法中。
从obj的waiting中释放一个或全部线程,对自身没有任何影响。
从obj的waiting中释放一个或全部线程,对自身没有任何影响。
经典问题
死锁
* 当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记,产生死锁。
* 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。
* 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。
生产者与消费者
若干个生产者在生产产品,这些产品将提供给若干个消费者去消费。
为了使生产者和消费者能并发执行,在两者之间设置一个能存储多个产品的缓冲区:
生产者将生产的产品放入缓冲区,消费者从缓冲区中取走产品进行消费。
显然生产者和消费者之间必须保持同步,
即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个满的缓冲区中放入产品。
为了使生产者和消费者能并发执行,在两者之间设置一个能存储多个产品的缓冲区:
生产者将生产的产品放入缓冲区,消费者从缓冲区中取走产品进行消费。
显然生产者和消费者之间必须保持同步,
即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个满的缓冲区中放入产品。
线程池
概念
问题:
* 线程是宝贵的内存资源、单个线程约占1MB的空间,过多分配易造成内存溢出;
* 频繁的创建及销毁会增加虚拟机回收频率、资源开销,造成程序性能下降。
* 线程是宝贵的内存资源、单个线程约占1MB的空间,过多分配易造成内存溢出;
* 频繁的创建及销毁会增加虚拟机回收频率、资源开销,造成程序性能下降。
线程池:
* 线程容器,可设定线程分配的数量上限;
* 将预先创建的线程对象存入池中,并重用线程池中的线程对象;
* 避免频繁的创建和销毁。
* 线程容器,可设定线程分配的数量上限;
* 将预先创建的线程对象存入池中,并重用线程池中的线程对象;
* 避免频繁的创建和销毁。
原理
将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。
线程池(接口/类)
位置:java.util.concurrent;
Executor接口
接口,线程池的顶级接口
ExecutorService接口
Executor的子接口,线程池接口
public interface ExecutorService
extends Executor
extends Executor
Future<?> submit(Runnable task)
// 该成员方法用于提交任务代码进而自动由线程池创建线程并运行
// 该成员方法用于提交任务代码进而自动由线程池创建线程并运行
Executors类
工厂/工具类,通过此类可以获得一个线程池
① 通过 Executors.newFixedThreadPool(int nThreads) 获取固定数量的线程池
@return ExecutorService 接口类型引用
@return ExecutorService 接口类型引用
② 通过 Executors.newCachedThreadPool()获得动态数量的线程池,如不够则创建新的,没有上限
@return ExecutorService 接口类型引用
@return ExecutorService 接口类型引用
互斥锁(接口/类)
位置:java.util.concurrent.locks;
Lock接口
public interface Lock {}
特点:
* 提供更多实用性方法,功能更强大、性能更优越。
* 提供更多实用性方法,功能更强大、性能更优越。
方法:
① void lock() // 获取锁,如锁被占用,则等待
② boolean trylock() // 尝试获取锁(成功true,失败false,不阻塞)
③ void unlock() // 释放锁
① void lock() // 获取锁,如锁被占用,则等待
② boolean trylock() // 尝试获取锁(成功true,失败false,不阻塞)
③ void unlock() // 释放锁
ReentrantLock类(重入锁/递归锁)
public class ReentrantLock extends Object implements Lock, Serializable
特点:
* Lock接口的实现类,与synchronized一样具有互斥锁功能。
注意:
1)使用Lock,需要显式的获取锁和释放锁;
2)为了避免拿到锁的线程在运行期间出现异常,导致程序终止没有释放锁!应用try-finally来保证无论是否出现异常,最终必须释放锁;
3)ReentrantLock为重入锁,避免递归,如果必须递归,必须正确控制退出条件。
(此锁支持同一线程的2147483647个递归锁的最大值。试图在Error超过这个限制的结果将从锁定的方法。)
* Lock接口的实现类,与synchronized一样具有互斥锁功能。
注意:
1)使用Lock,需要显式的获取锁和释放锁;
2)为了避免拿到锁的线程在运行期间出现异常,导致程序终止没有释放锁!应用try-finally来保证无论是否出现异常,最终必须释放锁;
3)ReentrantLock为重入锁,避免递归,如果必须递归,必须正确控制退出条件。
(此锁支持同一线程的2147483647个递归锁的最大值。试图在Error超过这个限制的结果将从锁定的方法。)
使用:①创建重入锁对象;②显式开启锁;③显式释放锁;④释放锁必须放在finally代码块中
ReentrantReadWriteLock类(读写锁)
public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable
特点:
* 一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁;
* 支持多次分配读锁,使多个读操作可以并发执行(写锁同步,读锁异步)。
* 一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁;
* 支持多次分配读锁,使多个读操作可以并发执行(写锁同步,读锁异步)。
互斥规则:
① 写-写:互斥,阻塞;-- 独占
② 读-写:互斥,读阻塞写、写阻塞读;
③ 读-读:不互斥、不阻塞;
* 在读操作远远高于写操作的环境下,可在保证线程安全的情况下,极大提高运行效率。
① 写-写:互斥,阻塞;-- 独占
② 读-写:互斥,读阻塞写、写阻塞读;
③ 读-读:不互斥、不阻塞;
* 在读操作远远高于写操作的环境下,可在保证线程安全的情况下,极大提高运行效率。
线程安全(方法/类)
方法
位置:java.util.Collections;
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
特点:
* 都是返回对应泛型集合类型的方法;
* 都是静态方法,通过Collections直接调用;
* 都是在静态方法中new了一个synchronized同步的静态内部类;
* 实际使用时的成员方法与原集合没有区别;
* JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现。
* 都是返回对应泛型集合类型的方法;
* 都是静态方法,通过Collections直接调用;
* 都是在静态方法中new了一个synchronized同步的静态内部类;
* 实际使用时的成员方法与原集合没有区别;
* JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现。
类
位置:java.util.concurrent;
CopyOnWriteArrayList类(线程安全的List)
public class CopyOnWriteArrayList<E>
extends Object
implements List<E>, RandomAccess, Cloneable, Serializable
extends Object
implements List<E>, RandomAccess, Cloneable, Serializable
特点:
* 符合List特点:有序、有下标、元素可重复
* 线程安全的ArrayList,加强版读写分离;
* 写有锁,读无锁,读写之间不阻塞,优于读写锁;
* 写入时,先copy一个容器副本、再添加新元素,最后替换引用;
* 使用方式与ArrayList无异。
* 符合List特点:有序、有下标、元素可重复
* 线程安全的ArrayList,加强版读写分离;
* 写有锁,读无锁,读写之间不阻塞,优于读写锁;
* 写入时,先copy一个容器副本、再添加新元素,最后替换引用;
* 使用方式与ArrayList无异。
List<String> alist = new CopyOnWriteArrayList<String>();
CopyOnWriteArraySet类(线程安全的Set)
public class CopyOnWriteArraySet<E>
extends AbstractSet<E>
implements Serializable
extends AbstractSet<E>
implements Serializable
说明:
* 符合Set特点:无序、无下标、元素不重复
* 线程安全的Set,底层使用CopyOnWriteArrayList实现;
* 唯一不同在于:使用addIfAbsent()添加元素(查重),会遍历数组;
* 如存在元素,则不添加(扔掉副本)。
* 符合Set特点:无序、无下标、元素不重复
* 线程安全的Set,底层使用CopyOnWriteArrayList实现;
* 唯一不同在于:使用addIfAbsent()添加元素(查重),会遍历数组;
* 如存在元素,则不添加(扔掉副本)。
Set<String> aset = new CopyOnWriteArraySet<String>();
ConcurrentHashMap类(线程安全的Map)
public class ConcurrentHashMap<K,V>
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable
特点:
* 初识容量默认为16段(Segment),使用分段锁设计;
* 不对整个Map加锁,而是为每个Segment加锁(16把锁);
* 当多个对象存入同一个Segment时,才需要互斥;
* 最理想状态位16个对象分别存入16个Segment,并行线程数量16个;
* 使用方式与HashMap无异。
// JDK1.7: 分段锁设计 Segment
// JDK1.8: CAS交换算法(CAS比较和交换) + 同步锁(锁的是表头)
* 初识容量默认为16段(Segment),使用分段锁设计;
* 不对整个Map加锁,而是为每个Segment加锁(16把锁);
* 当多个对象存入同一个Segment时,才需要互斥;
* 最理想状态位16个对象分别存入16个Segment,并行线程数量16个;
* 使用方式与HashMap无异。
// JDK1.7: 分段锁设计 Segment
// JDK1.8: CAS交换算法(CAS比较和交换) + 同步锁(锁的是表头)
Map<String, Integer> chmap = new ConcurrentHashMap<String, Integer>();
队列(FIFO)
位置:java.util.Queue;
Queue接口
public interface Queue<E> extends Collection<E>
* Collection的子接口,表示队列FIFO(First In First Out)
常用方法:
(1)抛出异常
boolean add(E e) // 顺序添加1个元素(到达上限后,再添加则会抛出异常)
E remove() // 获得第1个元素并移除(如果队列没有元素时,则抛异常)
E element() // 获得第1个元素但不移除(如果队列没有元素时,则抛异常)
(2)返回特殊值【推荐使用】
boolean offer(E e) // 顺序添加1个元素(到达上限后,再添加则会返回false)
E poll() // 获得第1个元素并移除(如果队列没有元素时,则返回null)
E keep() // 获得第一个元素但不移除(如果队列没有元素时,则返回null)
(1)抛出异常
boolean add(E e) // 顺序添加1个元素(到达上限后,再添加则会抛出异常)
E remove() // 获得第1个元素并移除(如果队列没有元素时,则抛异常)
E element() // 获得第1个元素但不移除(如果队列没有元素时,则抛异常)
(2)返回特殊值【推荐使用】
boolean offer(E e) // 顺序添加1个元素(到达上限后,再添加则会返回false)
E poll() // 获得第1个元素并移除(如果队列没有元素时,则返回null)
E keep() // 获得第一个元素但不移除(如果队列没有元素时,则返回null)
ConcurrentLinkedQueue(线程安全的队列Queue)
public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, Serializable
说明:
* 线程安全、可高效读写的队列,高并发下性能最好的队列;
* 无锁、CAS比较交换算法,修改的方法包含3个核心参数(V,E,N);
* V:要更新的变量、E:预期值、N:新值
* 只有当V==E时,V=N;否则表示已被更新过,则取消当前操作。
* 线程安全、可高效读写的队列,高并发下性能最好的队列;
* 无锁、CAS比较交换算法,修改的方法包含3个核心参数(V,E,N);
* V:要更新的变量、E:预期值、N:新值
* 只有当V==E时,V=N;否则表示已被更新过,则取消当前操作。
BlockingQueue接口(阻塞队列)
public interface BlockingQueue<E> extends Queue<E>
常用方法:
void put(E e) // 将指定元素插入此队列中,如果没有可用空间,则死等
E take() // 获取并移除此队列头部元素,如果没有可用元素,则死等
说明:
* Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法
* 可用于解决生产者、消费者问题
void put(E e) // 将指定元素插入此队列中,如果没有可用空间,则死等
E take() // 获取并移除此队列头部元素,如果没有可用元素,则死等
说明:
* Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法
* 可用于解决生产者、消费者问题
ArrayBlockingQueue类(有界阻塞队列)
* 数组结构实现,有界队列。手工固定上限
BlockingQueue<String> abq = new ArrayBlockingQueue<String>(3);
LinkedBlockingQueue类(无界阻塞队列)
* 链表结构实现,无界队列。默认上限Integer.MAX_VALUE
BlockingQueue<String> lbq = new LinkedBlockingQueue<String>();
CAS比较交换算法
比较与交换(compare and swap),是一种无锁算法,即不使用锁的情况下实现多线程之间的变量同步。
也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
CAS算法涉及到三个操作数:
需要读写的内存变量V、
进行比较的值(预期值)E、
拟写入的新值N。
当且仅当V的值等于E时,CAS通过原子方式用新值N来更新V值,否则不会执行任何操作(比较和替换是一个原子操作)。
一般情况下是一个自旋转操作,即不断的重试。
也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
CAS算法涉及到三个操作数:
需要读写的内存变量V、
进行比较的值(预期值)E、
拟写入的新值N。
当且仅当V的值等于E时,CAS通过原子方式用新值N来更新V值,否则不会执行任何操作(比较和替换是一个原子操作)。
一般情况下是一个自旋转操作,即不断的重试。
IO框架
字节流&字符流汇总图
流的概念
内存与存储设备之间传输数据的通道。
流的分类
按方向:【重点】相对于程序操作的内存,进入内存为输入,从内存出去为输出。
① 输入流:将[存储设备]中的内容输入到[内存]中;
② 输出流:将[内存]中的内容输出到[存储设备]中。
① 输入流:将[存储设备]中的内容输入到[内存]中;
② 输出流:将[内存]中的内容输出到[存储设备]中。
按单位:
① 字节流:以字节为单位,可以读写所有数据;
② 字符流:以字符为单位,只能读写文本数据。
① 字节流:以字节为单位,可以读写所有数据;
② 字符流:以字符为单位,只能读写文本数据。
按功能:
① 节点流:具有实际传输数据的读写功能;
② 过滤流:在节点流的基础之上增强功能。
① 节点流:具有实际传输数据的读写功能;
② 过滤流:在节点流的基础之上增强功能。
字节流
抽象父类
InputStream 字节输入流
OutputStream 字节输出流
InputStream 字节输入流
子类:字节节点流
FileInputStream 类
FileOutputStream 类
子类:字节过滤流(缓冲流)
BufferedInputStream 类
BufferedOutputStream 类
子类:字节过滤流(对象流)
ObjectInputStream 类
ObjectOutputStream 类
* 增强了缓冲区功能
* 增强了读写8种基本数据类型和字符串功能
* 增强了读写对象的功能:
1) Object readObject() // 从流中读取一个对象
2) void writeObject(Object obj) // 向流中写入一个对象
* 增强了读写8种基本数据类型和字符串功能
* 增强了读写对象的功能:
1) Object readObject() // 从流中读取一个对象
2) void writeObject(Object obj) // 向流中写入一个对象
对象序列化:
使用流传输对象的过程称为序列化、反序列化。
1)必须实现 Serializable 接口;
2)对象自身和类中属性都必须序列化
(即实现Serializable这个空接口即可,基本数据类型数组可不序列化,引用数据类型必须序列化);
3)transient 关键字修饰为临时属性,不参与序列化;
4)对象的默认序列化机制写入对象的类、类签名和所有非瞬态和非静态字段的值,
因此属性不能使用static修饰,否则取的都是最后一次的值(static属于类本身,会影响序列化)。
5)序列化对象流读取到文件尾,会抛出 EOFException 异常 - 捕获后停止读取文件。
使用流传输对象的过程称为序列化、反序列化。
1)必须实现 Serializable 接口;
2)对象自身和类中属性都必须序列化
(即实现Serializable这个空接口即可,基本数据类型数组可不序列化,引用数据类型必须序列化);
3)transient 关键字修饰为临时属性,不参与序列化;
4)对象的默认序列化机制写入对象的类、类签名和所有非瞬态和非静态字段的值,
因此属性不能使用static修饰,否则取的都是最后一次的值(static属于类本身,会影响序列化)。
5)序列化对象流读取到文件尾,会抛出 EOFException 异常 - 捕获后停止读取文件。
字符流
抽象父类
Reader 字符输入类
Writer 字符输出类
子类:字符过滤流
BufferedReader 字符输入过滤流
BufferedWriter 字符输出过滤流
PrintWriter 字符输出过滤流(写入后换行)【常用】
子类:桥转换流
InputStreamReader 桥转换输入流
OutputStreamWriter 桥转换输出流
* 可将字节流转换为字符流;(为的就是可以设置字符编码方式)
* 可指定字符的编码方式;
* 可指定字符的编码方式;
步骤
字节流转换字符流步骤:
①创建字节流 Output/InputStream
②创建过滤流,设置字符编码集(按需) OutputStreamWriter/InputStreamReader
③封装过滤流 PrintWriter/BufferedReader
④读写数据 write/read
⑤关闭流 close
①创建字节流 Output/InputStream
②创建过滤流,设置字符编码集(按需) OutputStreamWriter/InputStreamReader
③封装过滤流 PrintWriter/BufferedReader
④读写数据 write/read
⑤关闭流 close
一行套娃:
PrintWriter pw1 = new PrintWriter(new OutputStreamWriter(new FileOutputStream("files\\convert.txt"), "UTF-8"));
BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("files\\convert.txt"), "UTF-8"));
PrintWriter pw1 = new PrintWriter(new OutputStreamWriter(new FileOutputStream("files\\convert.txt"), "UTF-8"));
BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("files\\convert.txt"), "UTF-8"));
子类:字符节点输入输出流
FileReader 字符节点输入流
FileWriter 字符节点输出流
文件操作
File 类
* 文件和目录路径名的抽象表示形式。
* 没有无参构造。
* 具体方法都很常用,查询jdk1.8 API文档。
* 没有无参构造。
* 具体方法都很常用,查询jdk1.8 API文档。
FileFilter 接口
* 当调用File类中的listFiles()方法时,支持传入FileFilter接口的实现类对象,
对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中。——接口回调
对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中。——接口回调
简单FTP下载功能核心IO逻辑
Server Demo
Client Demo
网络编程
TCP/IP四层模型
应用层
应用层
表示层
会话层
传输层
传输层
网络层
网络层
网络接口层
数据链路层
物理层
IP协议
回环地址 127.0.0.1,指本机,一般用于测试。
查看IP命令:ipconfig
测试IP命令:ping D.D.D.D
Port
程序的唯一标识。
端口分类
公认端口 0-1023
注册端口 1024-49151
动态或私有端口 49152-65535
常用端口
MySql:3306
Oracle:1521
Tomcat:8080
SMTP:25
Web服务器:80
FTP服务器:21
类
InetAddress
标识花联网协议(IP)地址对象,封装了与该IP地址对象相关的所有信息,并提供常用方法
无法直接创建对象,构造方法私有化,需要通过getxxx方法获得
Inet4Address
Inet6Address
Socket
创建客户端的类
ServerSocket
创建服务器的类
开发步骤
① 建立通信连接(会话)
* 创建ServerSocket,指定端口号;
* 调用accept等待客户端接入;
② 客户端请求服务器
* 创建Socket,指定服务器IP + 端口号;
* 使用字节输出流,发送请求数据给服务器;
* 使用字节输入流,接收响应数据到客户端(等待);
③ 服务器响应客户端
* 使用字节输入流,接收请求数据到服务器(等待);
* 使用字节输出流,发送响应数据到客户端。
* 创建ServerSocket,指定端口号;
* 调用accept等待客户端接入;
② 客户端请求服务器
* 创建Socket,指定服务器IP + 端口号;
* 使用字节输出流,发送请求数据给服务器;
* 使用字节输入流,接收响应数据到客户端(等待);
③ 服务器响应客户端
* 使用字节输入流,接收请求数据到服务器(等待);
* 使用字节输出流,发送响应数据到客户端。
反射-设计模式
概念:程序运行时动态获取信息以及动态调用对象方法的功能为Java语言的反射机制。
类
Class类
String getName() 返回由 类对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。
static Class<?> forName(String className) 获取类对象名
Package getPackage() 获取类对象的包名
Class<? super T> getSuperclass() 获取父类的类对象名
Class<?>[] getInterfaces() 获取接口的类对象名
Constructor<?>[] getConstructors() 获取构造方法
Class<?>[] getParameterTypes() 获取方法(构造/成员)的参数类型列表
Field[] getFields() 获取属性(自身+父类的所有public公开属性)
Field[] getDeclaredFields() 获取属性(自身所有的属性)
Method[] getMethods() 获取方法(自身+父类单继承叠加的所有public公开方法)
Method[] getDeclaredMethods() 获取方法(自身所有的方法)
T newInstance() 创建由此类对象表示的类的新实例(此类对象必须有无参构造)
static Class<?> forName(String className) 获取类对象名
Package getPackage() 获取类对象的包名
Class<? super T> getSuperclass() 获取父类的类对象名
Class<?>[] getInterfaces() 获取接口的类对象名
Constructor<?>[] getConstructors() 获取构造方法
Class<?>[] getParameterTypes() 获取方法(构造/成员)的参数类型列表
Field[] getFields() 获取属性(自身+父类的所有public公开属性)
Field[] getDeclaredFields() 获取属性(自身所有的属性)
Method[] getMethods() 获取方法(自身+父类单继承叠加的所有public公开方法)
Method[] getDeclaredMethods() 获取方法(自身所有的方法)
T newInstance() 创建由此类对象表示的类的新实例(此类对象必须有无参构造)
Field类
Method类
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回单个指定方法名称和参数类型列表的方法(私有方法也可获取)
Object invoke(Object obj, Object... args)
调用底层的方法,这方法需要类的对象、实参列表。
返回单个指定方法名称和参数类型列表的方法(私有方法也可获取)
Object invoke(Object obj, Object... args)
调用底层的方法,这方法需要类的对象、实参列表。
Constructor类
获取 Class 对象并创建实例对象
类全名:Class.forName("全限定名");
编译期:类名.class;
运行时:对象名.getClass( );
创建类的实例对象:T newInstance( );
操作 构造方法 对象
Class<?> clazz = Class.forName("com.demo.reflect.User");
// 获取无参构造,创建对象
Constructor<?> c1 = clazz.getConstructor();
User u1 = (User) c1.newInstance();
// 获取有参构造,创建对象
Constructor<?> c2 = clazz.getConstructor(Integer.class, String.class);
User u2 = (User) c2.newInstance(1, "小叮当");
// 获取私有构造,创建对象
Constructor<?> c3 = clazz.getDeclaredConstructor(String.class);
c3.setAccessible(true); // 忽略访问修饰检查(突破封装)
User u3 = (User) c3.newInstance("小白");
// 获取无参构造,创建对象
Constructor<?> c1 = clazz.getConstructor();
User u1 = (User) c1.newInstance();
// 获取有参构造,创建对象
Constructor<?> c2 = clazz.getConstructor(Integer.class, String.class);
User u2 = (User) c2.newInstance(1, "小叮当");
// 获取私有构造,创建对象
Constructor<?> c3 = clazz.getDeclaredConstructor(String.class);
c3.setAccessible(true); // 忽略访问修饰检查(突破封装)
User u3 = (User) c3.newInstance("小白");
操作 成员变量 对象
Class<?> clazz = Class.forName("com.demo.reflect.User");
User user = (User) clazz.newInstance();
// 获取私有属性,设置属性的值
Field idField = clazz.getDeclaredField("id");
idField.setAccessible(true); // 忽略访问修饰检查(突破封装)
idField.set(user, 10); // 给user对象的值设置为10
int id = idField.get(user); // 从user对象中获取id的值
User user = (User) clazz.newInstance();
// 获取私有属性,设置属性的值
Field idField = clazz.getDeclaredField("id");
idField.setAccessible(true); // 忽略访问修饰检查(突破封装)
idField.set(user, 10); // 给user对象的值设置为10
int id = idField.get(user); // 从user对象中获取id的值
操作 成员方法 对象
Class<?> clazz = Class.forName("com.demo.reflect.User");
User user = (User) clazz.newInstance();
// 获取私有方法,调用执行该方法
Method setName = clazz.getMethod("setName", String.class);
setName.setAccessible(true); // 忽略访问修饰检查(突破封装)
setName.invoke(user, "小黑");
User user = (User) clazz.newInstance();
// 获取私有方法,调用执行该方法
Method setName = clazz.getMethod("setName", String.class);
setName.setAccessible(true); // 忽略访问修饰检查(突破封装)
setName.invoke(user, "小黑");
通用编程
反射执行任意实体类对象的 set 方法:Demo
反射执行任意实体类对象的 get 方法:Demo
反射执行任意实体类对象的任意方法:Demo
读取配置文件反射创建任意实体对象:Demo
设计模式
工厂模式
- 结合多态:扩展性更强
- 工厂模式:降低耦合度
- 反射机制:去代码冗余
// @param className 类的全限定名
public static Object createInstance(String className) throws Exception {
return Class.forName(className).newInstance( );
}
public static Object createInstance(String className) throws Exception {
return Class.forName(className).newInstance( );
}
Demo
单例模式
单例(singleton):只允许创建一个该类的对象。
饿汉式
天生线程安全(无锁)、类加载时创建(不用也创建,占用资源)
Demo
懒汉式
天生线程不安全(需同步锁、效率低)、使用时创建
Demo
懒汉式(线程安全版)
天生线程安全(无锁)、使用时创建(静态内部类)
Demo
代理模式
提供代理对象,增强方法功能。
静态代理设计模式
步骤:
① 自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
② 在代理类中声明被代理类的对象
③ 在代理类的方法中使用被代理类调用方法
① 自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
② 在代理类中声明被代理类的对象
③ 在代理类的方法中使用被代理类调用方法
优点:增强被代理类的功能,可以控制被代理类的对象
缺点:必须要重写被代理类接口的所有的方法(破坏单一职能原则,耦合性高)
缺点:必须要重写被代理类接口的所有的方法(破坏单一职能原则,耦合性高)
装饰者设计模式
步骤:
① 自定义一个装饰类(增强类)实现和被装饰类(被增强类)相同的接口
② 在装饰类中声明被装饰类的引用
③ 在装饰类的方法中使用被装饰类调用方法
① 自定义一个装饰类(增强类)实现和被装饰类(被增强类)相同的接口
② 在装饰类中声明被装饰类的引用
③ 在装饰类的方法中使用被装饰类调用方法
优点:增强被代理类的功能,无法控制被代理类的对象
缺点:必须要重写被装饰类接口的所有的方法(破坏单一职能原则,耦合性高)
缺点:必须要重写被装饰类接口的所有的方法(破坏单一职能原则,耦合性高)
动态代理设计模式
动态代理本质就是通过反射来生成的一个代理。
在Java中 java.lang.reflect 包下提供了一个 Proxy 类和 InvocationHandler 接口,通过使用这个类和接口就可以生成动态代理对象。
JDK提供的代理只能针对接口做代理,有更强大的代理cglib,Proxy类中的方法创建动态代理对象。
在Java中 java.lang.reflect 包下提供了一个 Proxy 类和 InvocationHandler 接口,通过使用这个类和接口就可以生成动态代理对象。
JDK提供的代理只能针对接口做代理,有更强大的代理cglib,Proxy类中的方法创建动态代理对象。
步骤:——基于接口的方法增强
① 编写一个代理类的接口
② 实现一个真正的代理类,实现该接口
③ 创建一个动态的代理类,实现 InvocationHandler 接口,并重写该 invoke() 方法
④ 在测试类中调用 Proxy.newProxyInstance() 方法生成动态代理对象
优化:③④可合并为匿名内部类实现。
① 编写一个代理类的接口
② 实现一个真正的代理类,实现该接口
③ 创建一个动态的代理类,实现 InvocationHandler 接口,并重写该 invoke() 方法
④ 在测试类中调用 Proxy.newProxyInstance() 方法生成动态代理对象
优化:③④可合并为匿名内部类实现。
优点:不需要重写接口中的所有方法,耦合度更低。
核心代码片段
/**
* 在代理实例上处理方法调用,并返回结果
* @param proxy 代理类的实例
* @param method 被代理类的原方法
* @param args 被代理类的原方法的实际参数
* @return Object对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object result = method.invoke(userDao, args);
System.out.println("日志记录");
return result;
}
* 在代理实例上处理方法调用,并返回结果
* @param proxy 代理类的实例
* @param method 被代理类的原方法
* @param args 被代理类的原方法的实际参数
* @return Object对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object result = method.invoke(userDao, args);
System.out.println("日志记录");
return result;
}
// ClassLoader loader: 被代理类对应的类加载器
// Class<?>[] interfaces: 被代理类所实现的所有接口
// InvocationHandler h: 一个用以增强代理类的处理器
接口名 p = (接口强转) Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
// Class<?>[] interfaces: 被代理类所实现的所有接口
// InvocationHandler h: 一个用以增强代理类的处理器
接口名 p = (接口强转) Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
// 匿名内部类对象 - 指定需要增强的方法
UserDao np = (UserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
(proxy, method, argss) -> {
String methodName = method.getName();
Object result;
// 只增强指定的需要增强的方法
if ("delete".equals(methodName)) {
System.out.println("权限校验");
result = method.invoke(userDao, argss);
System.out.println("日志记录");
} else {
result = method.invoke(userDao, argss);
}
return result;
});
np.delete();
UserDao np = (UserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
(proxy, method, argss) -> {
String methodName = method.getName();
Object result;
// 只增强指定的需要增强的方法
if ("delete".equals(methodName)) {
System.out.println("权限校验");
result = method.invoke(userDao, argss);
System.out.println("日志记录");
} else {
result = method.invoke(userDao, argss);
}
return result;
});
np.delete();
① Demo
② Demo
③ Demo
④ Demo
配置文件 + 工厂模式 + 反射 + 注解 + xml解析
Java8新特性
接口中的实现方法
① 使用 default 关键字就可以给接口增加一个非抽象的方法实现;
② 接口还可以存在 static 静态方法实现,使用 接口名.静态方法名 的形式直接调用;
* 包括声明 @FunctionalInterface 限制接口只有1个抽象方法时,也可以增加①或②。
* 一般不建议写实现。
Demo
Lambda 表达式
概念:允许把函数作为一个方法的参数,代码简洁紧凑(函数作为参数传递到方法中)
语法
函数式接口 变量名 = (参数1,参数2...)->{
//方法体
};
//方法体
};
新的操作符:-> (箭头操作符)
* 箭头操作符左侧 (参数1,参数2,...)-> 表示参数列表
* 箭头操作符 ->右侧{...} 表示方法体
* 箭头操作符左侧 (参数1,参数2,...)-> 表示参数列表
* 箭头操作符 ->右侧{...} 表示方法体
特点
* 形参列表的数据类型会自动推断
* 如果形参列表为空,只需保留()
* 如果形参列表只有1个参数,可以省略(),只要参数名字即可
* 如果执行语句只有1句,且无返回值,{}可以省略
* 若有返回值,仍想省略{},return也省略,必须保证执行语句为1句
* Lambda表达式不会生成单独的内部类文件
* Lambda表达式访问局部变量时,变量要修饰为final,如果没加会隐式自动添加
* Lambda表达式只能用在函数式接口的使用场景中
* 如果形参列表为空,只需保留()
* 如果形参列表只有1个参数,可以省略(),只要参数名字即可
* 如果执行语句只有1句,且无返回值,{}可以省略
* 若有返回值,仍想省略{},return也省略,必须保证执行语句为1句
* Lambda表达式不会生成单独的内部类文件
* Lambda表达式访问局部变量时,变量要修饰为final,如果没加会隐式自动添加
* Lambda表达式只能用在函数式接口的使用场景中
Demo
函数式接口
概念:如果一个接口只有 1 个公开抽象方法,则该接口为函数式接口。
* 为了确保接口达到只有1个方法的要求,接口名上添加注解 @FunctionalInterface
4 个核心函数式接口
位置:java.util.function
① Predicate<T>接口(断言、返回真假)
② Consumer<T>接口(消费、有去无回)
③ Supplier<T>接口(创造、无中生有)
④ Function<T,R>接口(传递、返回数据)
Demo
https://simple.blog.csdn.net/article/details/105000639
方法引用 ::
Lambda表达式的一种简写形式。
如果Lambda表达式方法体中只是调用一个特定的已存在的方法,则可以使用方法引用。
4 种使用形式
① 对象::实例方法
② 类::静态方法
③ 类::实例方法
④ 类::new
② 类::静态方法
③ 类::实例方法
④ 类::new
注意:调用的方法的参数列表与返回值类型,都与函数式接口中的方法参数列表与返回值类型一致。
Stream 接口
支持顺序和并行聚合操作的一系列元素,是Java8中处理数组、集合的抽象概念。
可以执行非常复杂的查找、过滤、映射等操作。
可以执行非常复杂的查找、过滤、映射等操作。
流(与I/O不同)
位置:java.util.stream
流程
创建.中间操作....最终操作
* 中间操作可.多个
主要的API方法
创建
Stream<T> stream = 集合或数组.stream();
中间操作
Stream<T> filter(Predicate<? super T> predicate)
返回由与此给定谓词匹配的此流的元素组成的流。
Stream<T> limit(long maxSize)
返回由此流的元素组成的流,截短长度不能超过 maxSize 。
Stream<T> distinct()
返回由该流的不同元素(根据 Object.equals(Object) )组成的流。
<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回由给定函数应用于此流的元素的结果组成的流。
Stream<T> sorted()
返回由此流的元素组成的流,根据自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator)
返回由该流的元素组成的流,根据提供的 Comparator进行排序。
返回由与此给定谓词匹配的此流的元素组成的流。
Stream<T> limit(long maxSize)
返回由此流的元素组成的流,截短长度不能超过 maxSize 。
Stream<T> distinct()
返回由该流的不同元素(根据 Object.equals(Object) )组成的流。
<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回由给定函数应用于此流的元素的结果组成的流。
Stream<T> sorted()
返回由此流的元素组成的流,根据自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator)
返回由该流的元素组成的流,根据提供的 Comparator进行排序。
最终操作
long count()
返回流中的元素个数。
void forEach(Consumer<? super T> action)
对此流的每个元素执行遍历操作。
boolean anyMatch(Predicate<? super T> predicate)
或,流中是否有包含指定规则的元素
boolean allMatch(Predicate<? super T> predicate)
且,流中是否全部包含指定规则的元素
boolean noneMatch(Predicate<? super T> predicate)
非,流中是否都不包含指定规则的元素
Optional<T> findFirst()
返回流的第一个元素的Optional,如果流为空,则返回一个空的Optional 。
Optional<T> findAny()
返回流的任意一个随机元素的Optional,如果流为空,则返回一个空的Optional 。
Optional<T> max(Comparator<? super T> comparator)
根据提供的 Comparator 返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator)
根据提供的 Comparator 返回此流的最小元素。
返回流中的元素个数。
void forEach(Consumer<? super T> action)
对此流的每个元素执行遍历操作。
boolean anyMatch(Predicate<? super T> predicate)
或,流中是否有包含指定规则的元素
boolean allMatch(Predicate<? super T> predicate)
且,流中是否全部包含指定规则的元素
boolean noneMatch(Predicate<? super T> predicate)
非,流中是否都不包含指定规则的元素
Optional<T> findFirst()
返回流的第一个元素的Optional,如果流为空,则返回一个空的Optional 。
Optional<T> findAny()
返回流的任意一个随机元素的Optional,如果流为空,则返回一个空的Optional 。
Optional<T> max(Comparator<? super T> comparator)
根据提供的 Comparator 返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator)
根据提供的 Comparator 返回此流的最小元素。
串行流
.stream()
并行流
.parallelStream()
比串行流的效率更高
集合体系
Colleciton
List
ArrayList
Vector
LinkedList
CopyOnWriteArrayList
Set
HashSet
LinkedHashSet
SortedSet
TreeSet
AbstractSet
CopyOnWriteArraySet
Queue
ConcurrentLinkedQueue
AbstractQueue
抽象类
BlockingQueue
抽象类
BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
Map
HashMap
LinkedHashMap
Hashtable
Properties
AbstractMap
TreeMap
ConcurrentHashMap
Collections
排序
public static <T extends Comparable<? super T>> void sort(List<T> list)
public static void reverse(List<?> list)
public static void shuffle(List<?> list)
public static void reverse(List<?> list)
public static void shuffle(List<?> list)
同步
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
其他诸如检查、判空、最大小值、交换等... API文档。
字节流体系
OutputStream
FileOutputStream (fn)
FilterOutputStream
BufferedOutputStream (fos)
ObjectOutputStream (fos)
InputStream
FileInputStream (fn)
FilterInputStream
BufferedInputStream (fis)
ObjectInputStream (fis)
字符流体系
Writer
BufferedWriter
OutputStreamWriter (fos)
FileWriter (fn)
PrintWriter (osw)
Reader
InputStreamReader (fis)
FileReader (fn)
BufferedReader (isr)
JavaWeb
MySQL
概念
关系结构数据库:Oracle、DB2、MySQL、SQL Server。
以表格(Table)存储,多表间建立关联关系,通过分类、合并、连接、选取等运算实现访问。
以表格(Table)存储,多表间建立关联关系,通过分类、合并、连接、选取等运算实现访问。
DBMS,数据库管理系统。
MySQL:免费、适合中小型企业(被Oracle收购)。
在 WEB 应用方面,MySQL是最好的 RDBMS(关系数据库管理系统)应用软件之一。
MySQL:免费、适合中小型企业(被Oracle收购)。
在 WEB 应用方面,MySQL是最好的 RDBMS(关系数据库管理系统)应用软件之一。
获取
官方网站:https://www.mysql.com/
下载地址:https://dev.mysql.com/downloads/mysql/
安装包名:mysql-installer-community-5.7.28.0.msi
* MySQL57,即5.7版本应用较为广泛。
下载地址:https://dev.mysql.com/downloads/mysql/
安装包名:mysql-installer-community-5.7.28.0.msi
* MySQL57,即5.7版本应用较为广泛。
安装
详细安装步骤
https://simple.blog.csdn.net/article/details/105099985
配置
环境变量
Win
1. 创建MYSQL_HOME : C:\Program Files\MySQL\MySQL Server 5.7
2. 追加Path:%MYSQL_HOME%\bin;
2. 追加Path:%MYSQL_HOME%\bin;
Mac
* 终端中输入cd ~ 进入目录,并检查.bash_profile是否存在,有则追加,无则创建
* 创建文件 touch .bash_profile
* 打开文件 open .bash_profile
* 输入export PATH=${PATH}:/usr/local/mysql/bin 保存并退出终端
* 创建文件 touch .bash_profile
* 打开文件 open .bash_profile
* 输入export PATH=${PATH}:/usr/local/mysql/bin 保存并退出终端
配置参数
C:\ProgramData\MySQL\MySQL Server 5.7\my.ini
default-character-set
客户端默认字符集,默认被注释,即遵循环境的字符集
character-set-server
服务器端默认字符集,默认被注释,即遵循环境的字符集
port
客户端和服务器端的端口号,默认 port=3306
default-storage-engine
MySQL默认存储引擎 INNODB
解决插入中文数据乱码或问号的问题
[mysql] # 第一处 line67
default-character-set=utf8
default-character-set=utf8
[mysqld] # 第二处 line102
character-set-server=utf8
collation-server=utf8_general_ci
character-set-server=utf8
collation-server=utf8_general_ci
重启MySQL服务:
win> net stop mysql57 && net start mysql57
Linux$ service mysql restart
win> net stop mysql57 && net start mysql57
Linux$ service mysql restart
启动
win> net start mysql57
修改root密码
旧版(mysql57可用):root可替换为其他用户名
SET PASSWROD FOR root@localhost = PASSWORD('123456');
新版:
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
SET PASSWROD FOR root@localhost = PASSWORD('123456');
新版:
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
客户端工具
Navicate
快速、可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。
* 使用 Navicate 需要会pj
* 使用 Navicate 需要会pj
SQLyog
广泛的预定义工具和查询、友好的视觉界面、类似 Excel 的查询结果编辑界面。
DataGrip
IDEA开发工具集成。
DataGrip是捷克公司的产品,需要付费。如果买了IDEA,DataGrip通用。
DataGrip是捷克公司的产品,需要付费。如果买了IDEA,DataGrip通用。
SQL语言分类
1. 数据`查询`语言 `DQL`(Data Query Language):select、where、order by、group by、having
2. 数据`定义`语言 `DDL`(Data Definition Language):create、alter、drop
3. 数据`操作`语言 `DML`(Data Manipulation Language):insert、update、delete
4. 事务`处理`语言 `TPL`(Transaction Process Language):commit、rollback
5. 数据`控制`语言 `DCL`(Data Control Language):grant、revoke
2. 数据`定义`语言 `DDL`(Data Definition Language):create、alter、drop
3. 数据`操作`语言 `DML`(Data Manipulation Language):insert、update、delete
4. 事务`处理`语言 `TPL`(Transaction Process Language):commit、rollback
5. 数据`控制`语言 `DCL`(Data Control Language):grant、revoke
命令
查询
基本查询
SELECT 列名 FROM 表名;
运算 + - * / 没有 %(它现在是占位符)
列 AS '列别名'
DISTINCT 列名
排序查询
SELECT 列名 FROM 表名 ORDER BY 排序列1 [排序规则], 排序列2 [排序规则]
排序规则
ASC 升序
DESC 降序
条件查询
SELECT 列名 FROM 表名 WHERE 条件
等值判断 =
不等值判断 >、<、>=、<=、!=、<>(也是不等)
逻辑判断 AND, OR, NOT
区间判断 BETWEEN ... AND ...
包含两端边界两个值
小到大顺序不能颠倒
NULL值判断 IS NULL, IS NOT NULL
枚举查询 IN(值1, 值2, 值3..)
模糊查询
列名 LIKE 'S_'
_ 单个任意字符,模糊内容、精确长度
列名 LIKE 'S%'
% 0或多个任意字符0-n个
分支结构查询
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
WHEN 条件3 THEN 结果3
ELSE 结果x
END AS '列别名'
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
WHEN 条件3 THEN 结果3
ELSE 结果x
END AS '列别名'
对紧跟列名的操作,注意列名后的 逗号
时间查询
SELECT 时间函数([参数列表]);
SYSDATE() / NOW() 年-月-日 时:分:秒
CURDATE() 年-月-日
CURTIME() 时:分:秒
WEEK(DATE) 获取指定日期为一年中的第几周
YEAR(DATE) / MONTH(DATE) / DAY(DATE) 年、月、日
HOUR(TIME) / MINUTE(TIME) / SECOND(TIME) 时、分、秒
DATEDIFF(DATE1, DATE2) 两个日期的相隔天数
ADDDATE(DATE, N) 计算DATE加上N天后的日期(自然日)
CURDATE() 年-月-日
CURTIME() 时:分:秒
WEEK(DATE) 获取指定日期为一年中的第几周
YEAR(DATE) / MONTH(DATE) / DAY(DATE) 年、月、日
HOUR(TIME) / MINUTE(TIME) / SECOND(TIME) 时、分、秒
DATEDIFF(DATE1, DATE2) 两个日期的相隔天数
ADDDATE(DATE, N) 计算DATE加上N天后的日期(自然日)
聚合函数
SELECT 聚合函数(列名) FROM 表名;
COUNT(列) 总行数,忽略null值
SUM(列) 所有行中单列结果的综合
AVG(列) 平均值
MAX(列) 最大值
MIN(列) 最小值
SUM(列) 所有行中单列结果的综合
AVG(列) 平均值
MAX(列) 最大值
MIN(列) 最小值
分组查询
SELECT 列名 FROM 表名 WHERE 条件 GROUP BY 分组依据列;
WHERE 条件 也可省略。
分组过滤查询
SELECT 列名 FROM 表名 WHERE 条件 GROUP BY 分组列 HAVING 过滤规则;
过滤规则:定义对分组后的数据进行过滤,相当于一个新的条件。
字符串查询
SELECT 字符串函数([参数列表]);
CONCAT(str1, str2, str...) 连接多个字符串
INSERT(str, pos, len, newstr) 将str中指定pos位置开始的len长度的内容替换为newstr
LOWER(str) 转小写
UPPER(str) 转大写
SUBSTRING(str, pos) / (str FROM pos) / (str, pos, len) / (str FROM pos FOR len)
将str字符串中指定pos位置开始截取到末尾或者len长度的内容
INSERT(str, pos, len, newstr) 将str中指定pos位置开始的len长度的内容替换为newstr
LOWER(str) 转小写
UPPER(str) 转大写
SUBSTRING(str, pos) / (str FROM pos) / (str, pos, len) / (str FROM pos FOR len)
将str字符串中指定pos位置开始截取到末尾或者len长度的内容
* 注意:MySQL 中字符串下标是从 1 开始。
限定查询
SELECT 列名 FROM 表名 LIMIT 起始行,查询行数;
* 注意:LIMIT 的起始行是从 0 开始为第1 行。
【公式】第 i 页: SELECT * FROM LIMIT 页长*(i-1), 页长
【查询总结】
SELECT 列名 FROM 表名
WHERE 条件 GROUP BY 分组 HAVING 过滤条件
ORDER BY 排序列 LIMIT 起始行,总条数;
WHERE 条件 GROUP BY 分组 HAVING 过滤条件
ORDER BY 排序列 LIMIT 起始行,总条数;
执行顺序:
⑤ SELECT 列名
① FROM 表名
② WHERE 条件
③ GROUP BY 分组
④ HAVING 过滤条件
⑥ORDER BY 排序列(asc|desc)
⑦LIMIT 起始行,总条数
⑤ SELECT 列名
① FROM 表名
② WHERE 条件
③ GROUP BY 分组
④ HAVING 过滤条件
⑥ORDER BY 排序列(asc|desc)
⑦LIMIT 起始行,总条数
子查询
子查询结果作为条件判断
SELECT 列名 FROM 表名 WHERE 条件 > (子查询结果值);
子查询结果:一行一列(1个值)
子查询结果作为枚举查询条件
SELECT 列名 FROM 表名 WHERE 列名 IN(子查询结果列);
子查询结果:多行单列(1列值) - IN可替换为 ANY 或 ALL 关键字
子查询结果作为一张表
SELECT 列名 FROM (子查询结果表) AS 表别名;
子查询结果:多行多列(1张表)
合并查询
去重合并
SELECT * FROM 表名 1 UNION SELECT * FROM 表名 2
全部合并
SELECT * FROM 表名1 UNION ALL SELECT * FROM 表名2
列数必须相同,行内容向下追加。
表连接查询
SELECT 列名 FROM 表1 连接方式 表2 ON 连接条件;
四种连接方式
内连接方式: INNER JOIN ... ON ...
内连接多表: INNER JOIN ... INNER JOIN ... ON ...
外连接左表: LEFT JOIN ... ON ...
外连接右表: RIGHT JOIN ... ON ...
库表
库操作
库中的数据类型
数值类型:INT / DOUBLE / DOUBLE(M,D) / DECIMAL(M,D)
日期类型:DATE / TIME / YEAR / DATETIME / TIMESTAMP
字符串类型:CHAR / VARCHAR / BOLB / TEXT
查看所有数据库
SHOW DATABASES; #显示当前MySQL中包含的所有数据库
创建自定数据库
CREATE DATABASE mydb1; #创建mydb数据库
CREATE DATABASE mydb2 CHARACTER SET gbk; #创建数据库并设置编码格式gbk【常用】
CREATE DATABASE mydb3 CHARACTER SET gbk COLLATE gbk_chinese_ci; #支持简体中文和繁体中文
CREATE DATABASE IF NOT EXISTS mydb4; #如果mydb4数据库不存在,则创建;如果存在,则不创建。
CREATE DATABASE mydb2 CHARACTER SET gbk; #创建数据库并设置编码格式gbk【常用】
CREATE DATABASE mydb3 CHARACTER SET gbk COLLATE gbk_chinese_ci; #支持简体中文和繁体中文
CREATE DATABASE IF NOT EXISTS mydb4; #如果mydb4数据库不存在,则创建;如果存在,则不创建。
查看库创建信息
SHOW CREATE DATABASE mydb2; #查看创建数据库时的基本信息
修改数据库信息
ALTER DATABASE mydb2 CHARACTER SET utf8; # 修改mydb1 的字符集为 utf-8
删除指定数据库
DROP DATABASE mydb1; #删除数据库mydb1
查看使用数据库
SELECT DATABASE( ); #查看当前使用的数据库
切换使用数据库
USE mydb1; #使用mydb1数据库
表操作
创建自定数据表
CREATE TABLE 表名(
列名1 数据类型 [约束],
列名1 数据类型 [约束],
...
列名n 数据类型 [约束] # 最后一行不加逗号
)[CHARSET = utf8]; # 可根据需要指定表的字符编码集
列名1 数据类型 [约束],
列名1 数据类型 [约束],
...
列名n 数据类型 [约束] # 最后一行不加逗号
)[CHARSET = utf8]; # 可根据需要指定表的字符编码集
【DML】
DML:增、删、改
创建
INSERT INTO 表名(列 1,列 2,列 3....) VALUES(值 1,值 2,值 3......);
* 表名后的列名和 VALUES 里的`值要一一对应`(个数、顺序、类型)
查看表创建信息
SHOW CREATE TABLE student; #查看创建数据表时的信息:列名和类型
修改
UPDATE 表名 SET 列1 = 新值1, 列2 = 新值2, ... WHERE 条件;
* 注意:SET 后多个列名=值,绝大多数情况下都要`加 WHERE 条件`,指定修改,`否则为整表更新`。
列的增删改
# 【增】最右侧添加:如果想在一个已经建好的表中添加一列,可以用
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL;
# 【增】指定位置添加:这条语句向已有的表中加入新的一列,这一列在表的最后一列位置,希望添加在指定的一列
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL AFTER COLUMN_NAME;
# 【增】添加到第一列:上面这个命令的意思是说添加新列到某一列后面。如果想添加到第一列
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL FIRST;
# 【改】将表 mydb1 中,列名 def 改为unit
ALTER TABLE mydb1 CHANGE def unit CHAR;
# 【删】将表 mydb1 中,列名 unit 的列删除
ALTER TABLE mydb1 DROP COLUMN unit;
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL;
# 【增】指定位置添加:这条语句向已有的表中加入新的一列,这一列在表的最后一列位置,希望添加在指定的一列
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL AFTER COLUMN_NAME;
# 【增】添加到第一列:上面这个命令的意思是说添加新列到某一列后面。如果想添加到第一列
ALTER TABLE mydb1 ADD COLUMN NEW_COLUMN_NAME VARCHAR(45) NOT NULL FIRST;
# 【改】将表 mydb1 中,列名 def 改为unit
ALTER TABLE mydb1 CHANGE def unit CHAR;
# 【删】将表 mydb1 中,列名 unit 的列删除
ALTER TABLE mydb1 DROP COLUMN unit;
删除
DELETE FROM 表名 WHERE 条件;
* 注意:删除时,`必须加 WHERE 条件`,如若不加 WHERE条件,删除的是整张表的数据
* 注意:仅仅删除数据,不会影响数据表的结构
* 注意:仅仅删除数据,不会影响数据表的结构
清空
TRUNCATE TABLE 表名;
* 注意:TRUNCATE 是`把表销毁`,再按照原表的格式`创建一张新表`
约束
实体完整性约束
* 标识每一列数据不重复、实体唯一。
主键约束
PRIMARY KEY
列值:不可重复,不能为 NULL
唯一约束
UNIQUE
列值:不可重复,可以为 NULL
自动增长列
AUTO_INCREMENT
列值:从 1 开始,每次加 1;不能单独使用,和主键配合
域完整性约束
* 限制列的单元格的数据正确性。
非空约束
NOT NULL
列值:必须有值,不能为 NULL
默认值约束
DEFAULT
列值:为列赋予默认值;书写DEFAULT,以指定的默认值进行填充
引用完整性约束
CONSTRAINT 引用名 FOREIGN KEY(列名) REFERENCES 被引用表名(列名)
列值:FOREIGN KEY 引用外部表的某个列的值,新增数据时,约束此列的值必须是引用表中存在的值
事务
概念
事务,是一个原子操作,是一个最小执行单元,可以由一个或多个SQL语句组成。
在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功,有一个SQL语句执行失败,整个事务都执行失败。
在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功,有一个SQL语句执行失败,整个事务都执行失败。
边界
开始:
上一个事务结束后的第一条增删改的语句,即事务的开始。
# 1.开启事务 方式一:
START TRANSACTION;
# 1.开启事务 方式二:
SET autoCommit = 0; # autoCommit = 0 关闭自动提交,1 开启自动提交
上一个事务结束后的第一条增删改的语句,即事务的开始。
# 1.开启事务 方式一:
START TRANSACTION;
# 1.开启事务 方式二:
SET autoCommit = 0; # autoCommit = 0 关闭自动提交,1 开启自动提交
结束:
1). 提交:
a. 显示提交:COMMIT;
b. 隐式提交:一条创建/删除的语句,正常退出(客户端退出连接);
2). 回滚:
a. 显示回滚:ROLLBACK;
b. 隐式回滚:非正常退出(断电/宕机)执行了创建/删除语句,但是失败了,会为这个无效的语句执行回滚。
1). 提交:
a. 显示提交:COMMIT;
b. 隐式提交:一条创建/删除的语句,正常退出(客户端退出连接);
2). 回滚:
a. 显示回滚:ROLLBACK;
b. 隐式回滚:非正常退出(断电/宕机)执行了创建/删除语句,但是失败了,会为这个无效的语句执行回滚。
原理
数据库会为每一个客户端都维护一个`空间独立的缓存区`(回滚段)。
一个事务中所有的增删改语句的`执行结果都会缓存在回滚段`中,
只有当事务中所有 SQL 语句均`正常结束`(commit),
才会将回滚段中的数据同步到数据库。否则无论因为哪种原因失败,整个事务将回滚(rollback)。
一个事务中所有的增删改语句的`执行结果都会缓存在回滚段`中,
只有当事务中所有 SQL 语句均`正常结束`(commit),
才会将回滚段中的数据同步到数据库。否则无论因为哪种原因失败,整个事务将回滚(rollback)。
特性(ACID)
Atomicity(原子性)
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败。
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败。
Consistency(一致性)
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态。
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态。
Isolation(隔离性)
事务查看数据操作时数据所处的状态,要么是另一并发事务修改它之前的状态,
要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
事务查看数据操作时数据所处的状态,要么是另一并发事务修改它之前的状态,
要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
Durability(持久性)
持久性事务完成之后,它对于系统的影响是永久性的。
持久性事务完成之后,它对于系统的影响是永久性的。
应用&实例
应用环境:
基于增删改语句的操作结果(均返回操作后受影响的行数),
可通过程序逻辑手动控制事务提交或回滚。
基于增删改语句的操作结果(均返回操作后受影响的行数),
可通过程序逻辑手动控制事务提交或回滚。
模拟转账 Demo
权限
创建用户
CREATE USER 用户名 IDENTIFIED BY 密码;
授权用户
GRANT ALL ON 数据库.表 TO 用户名;
撤销授权
REVOKE ALL ON 数据库.表名 FROM 用户名;
删除用户
DROP USER 用户名;
视图
概念
视图,`虚拟表`,从一个表或多个表中查询出来的表,作用和真实表一样,`包含一系列带有行和列的数据`。
视图中,用户可以使用 SELECT 语句查询数据,也可以使用 INSERT、UPDATE、DELETE 修改记录(影响原表),
视图可以使用户操作方便,并保障数据库系统安全。
视图中,用户可以使用 SELECT 语句查询数据,也可以使用 INSERT、UPDATE、DELETE 修改记录(影响原表),
视图可以使用户操作方便,并保障数据库系统安全。
特点
优点
- 简单化,数据所见即所得。
- 安全性,用户只能查询或修改他们所能见到得到的数据。
- 逻辑独立性,可以屏蔽真实表结构变化带来的影响。
- 安全性,用户只能查询或修改他们所能见到得到的数据。
- 逻辑独立性,可以屏蔽真实表结构变化带来的影响。
缺点
- 性能相对较差,简单的查询也会变得稍显复杂。
- 修改不方便,特变是复杂的聚合视图基本无法修改。
- 修改不方便,特变是复杂的聚合视图基本无法修改。
创建
CREATE VIEW 视图名 AS 查询数据源表语句;
使用
SELECT * 与正常的 TABLE 使用方式相同
修改
方式① CREATE OR REPLACE VIEW 视图名 AS 查询语句;
方式② ALTER VIEW 视图名 AS 查询语句;
方式② ALTER VIEW 视图名 AS 查询语句;
删除
DROP VIEW 视图名;
JDBC
概念
JDBC(Java DataBase Connectivity) Java连接数据库,可以使用Java语言连接数据库完成 CRUD 操作。
CRUD:增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)
CRUD:增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)
核心思想
Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。
由数据库厂商提供驱动实现类(Driver数据库驱动)
由数据库厂商提供驱动实现类(Driver数据库驱动)
Driver: mysql-connector-java-5.1.X 适用于5.X版本
Driver: mysql-connector-java-8.0.X 适用于8.X版本
Driver: mysql-connector-java-8.0.X 适用于8.X版本
API
环境搭建
1. 在项目下新建 lib 文件夹,用于存放 jar 文件
2. 复制MySQL驱动文件 mysql-connector-java-5.1.25-bin.jar 到项目的 lib 文件夹中
3. 选中 lib 文件夹,右键选择 add as library,点击OK
2. 复制MySQL驱动文件 mysql-connector-java-5.1.25-bin.jar 到项目的 lib 文件夹中
3. 选中 lib 文件夹,右键选择 add as library,点击OK
5.x 链接:https://pan.baidu.com/s/1pB0xoNHDt2NxCX0fgA4ezg
提取码:48t6
8.x 链接:https://pan.baidu.com/s/1FWzpLm1XUqCFKkVt9KDINA
提取码:d5b3
提取码:48t6
8.x 链接:https://pan.baidu.com/s/1FWzpLm1XUqCFKkVt9KDINA
提取码:d5b3
开发步骤
1. 加载驱动
// 反射:触发类加载,Driver 执行了 static 代码块
Class.forName("com.mysql.jdbc.Driver");
Class.forName("com.mysql.jdbc.Driver");
2. 连接数据库
// 数据库连接地址,兼容中文正确显示的参数:?useUnicode=true&characterEncoding=utf8
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8";
String user = "root"; // 用户名
String password = "admin123"; // 密码
Connection connection = DriverManager.getConnection(url, user, password);
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8";
String user = "root"; // 用户名
String password = "admin123"; // 密码
Connection connection = DriverManager.getConnection(url, user, password);
3. 获取发送 SQL 语句的对象
// 普通对象
Statement statement = connection.createStatement();
//【使用】预编译SQL语句;安全地避免SQL注入;动态填充数据执行多个同构的SQL语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.set类型(下标,值); // String sql = "...?...?...?"; 下标: 对应问号占位符 1 2 3
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.set类型(下标,值); // String sql = "...?...?...?"; 下标: 对应问号占位符 1 2 3
4. 编写并执行 SQL 语句
// DML(增删改)操作
int result = preparedStatement.executeUpdate();
int result = preparedStatement.executeUpdate();
// DQL(查询)操作
ResultSet resultSet = preparedStatement.executeQuery();
ResultSet resultSet = preparedStatement.executeQuery();
5. 处理结果
if (result > 0) { /* 执行成功 */ } else { /* 执行失败 */ }
if (resultSet.next()) {
类型 变量 = resultSet.get类型(int columnIndex); // 列的编号从1开始
类型 变量 = resultSet.get类型(String columnLable); // 列名
} else {
/* 查询失败 */
}
类型 变量 = resultSet.get类型(int columnIndex); // 列的编号从1开始
类型 变量 = resultSet.get类型(String columnLable); // 列名
} else {
/* 查询失败 */
}
6. 关闭资源
// 原则:先开后闭
非空 resultSet.close();
非空 preparedStatement.close();
非空 connection.close();
非空 resultSet.close();
非空 preparedStatement.close();
非空 connection.close();
封装连接
重用性方案
封装了获取连接、释放资源两个方法:
public static Connection getConnection( )
public static void closeAll(Connection c, Statement s, ResultSet r)
public static Connection getConnection( )
public static void closeAll(Connection c, Statement s, ResultSet r)
DBUtils.java - Demo
跨平台方案
定义 private static final Properties properties = new Properties(); // 配置文件集合
定义 static{
// 首次使用工具类,触发类加载
InputStream is = DBUtils.class.getResourceAsStream("文件路径"); // 复用本类自带流,读取配置文件
properties.load(is); // 将is流中的配置文件信息,加载到集合中
Class.forName(properties.getProperty("driver"));
}
在 getConnection 方法中应用 properties.getProperty("url"); // 以及 username 和 password
定义 static{
// 首次使用工具类,触发类加载
InputStream is = DBUtils.class.getResourceAsStream("文件路径"); // 复用本类自带流,读取配置文件
properties.load(is); // 将is流中的配置文件信息,加载到集合中
Class.forName(properties.getProperty("driver"));
}
在 getConnection 方法中应用 properties.getProperty("url"); // 以及 username 和 password
DBUtils.java - Demo
src/db.properties - Demo
优化封装事务
DBUtils.java - Demo
封装数据
ORM 思想:零散数据的载体
概念:Object Relational Mapping,对象关系映射。
将数据库查询到的结果集遍历映射为对象集合。
entity规则:表名=类名;列名=属性名;提供各个属性的get/set方法;提供无参构造和[若需有参构造]
将数据库查询到的结果集遍历映射为对象集合。
entity规则:表名=类名;列名=属性名;提供各个属性的get/set方法;提供无参构造和[若需有参构造]
Demo
DAO 层:数据访问对象
概念:Data Access Object,数据访问对象。
1. 将所有对同一张表的操作都封装在一个 XXXDaoImpl对象中;
2. 根据增删改查的不同功能,实现具体的方法(insert, update, delete, select, selectAll);
经验:应将对于一张表的所有操作统一封装在一个数据访问对象中。——重用!
1. 将所有对同一张表的操作都封装在一个 XXXDaoImpl对象中;
2. 根据增删改查的不同功能,实现具体的方法(insert, update, delete, select, selectAll);
经验:应将对于一张表的所有操作统一封装在一个数据访问对象中。——重用!
Demo
日期转换
分类
String 类型,用户输入类型
java.util.Date 类型,java应用层的日期类型
java.sql.Date 类型,java的MySQL中特殊日期类型
String → java.util.Date
日期格式化类: SimpleDateFormat
//按照指定格式转换成util.Date类型
String dateStr = "1999-09-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = sdf.parse(dateStr);
String dateStr = "1999-09-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = sdf.parse(dateStr);
java.util.Date → java.sql.Date
// java.sql.Date(long mesc) 参数为毫秒值的有参构造
public static java.sql.Date utilToSql(java.util.Date date) {
return new java.sql.Date(date.getTime());
}
public static java.sql.Date utilToSql(java.util.Date date) {
return new java.sql.Date(date.getTime());
}
java.sql.Date → java.util.Date
// 无需转换:父类引用指向子类对象
java.util.Date utilDate = new java.sql.Date(long msec); // mesc: 毫秒值
// eg:
java.util.Date user_borndate = resultSet.getDate("user_borndate");
java.util.Date utilDate = new java.sql.Date(long msec); // mesc: 毫秒值
// eg:
java.util.Date user_borndate = resultSet.getDate("user_borndate");
数据库连接池
自定义连接池普通版
步骤:
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.获取连接,LinkedList.remove(0)
3.归还连接,addBack(connection)
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.获取连接,LinkedList.remove(0)
3.归还连接,addBack(connection)
Demo
自定义连接池优化版
步骤:
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.加入装饰者设计模式,将普通连接对象Connection中的close方法改变成归还连接
> 破坏单一职责原则,使用了中间类
3.获取连接,使用装饰者设计模式,返回增强的连接对象
4.归还连接,就无序addBack(connection)方法
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.加入装饰者设计模式,将普通连接对象Connection中的close方法改变成归还连接
> 破坏单一职责原则,使用了中间类
3.获取连接,使用装饰者设计模式,返回增强的连接对象
4.归还连接,就无序addBack(connection)方法
自定义连接池终极版
步骤:
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.加入动态代理,将普通连接对象Connection中的close方法改变成归还连接
3.获取连接,使用动态dialing,返回增强的连接对象
1.连接池初始化时,创建一些连接,并存储到 LinkedList中
2.加入动态代理,将普通连接对象Connection中的close方法改变成归还连接
3.获取连接,使用动态dialing,返回增强的连接对象
Demo
Druid 德鲁伊环境配置
特点
Druid 是目前比较流行高性能的,分布式列存储
一、亚秒级查询
二、实时数据注入
三、可扩展的PB级存储
四、多环境部署
五、丰富的社区
一、亚秒级查询
二、实时数据注入
三、可扩展的PB级存储
四、多环境部署
五、丰富的社区
导入jar包:druid-1.1.5.jar
链接:https://pan.baidu.com/s/1f0pl7CnEJ5vNkWGFS3kdrg
提取码:05wc
提取码:05wc
配置文件:database.properties
DBPoolUtils.java
Service业务(Biz/Business)
概念:用户要完成的一个业务功能,是由一个或多个的DAO调用组成。
软件、程序提供的一个功能都叫业务
软件、程序提供的一个功能都叫业务
UserInfoServiceImpl.java Demo
ThreadLocal 类解决转账事务
简介
ThreadLocal 可以绑定当前线程与1个泛型对象的键值对的对象。
常用方法:
1. public void set(T value); // 设置当前线程绑定的对象
2. public T get(); // 返回当前线程绑定的对象
3. public void remove(); // 移除当前线程的绑定对象
常用方法:
1. public void set(T value); // 设置当前线程绑定的对象
2. public T get(); // 返回当前线程绑定的对象
3. public void remove(); // 移除当前线程的绑定对象
转账基本流程
1. 验证 fromAccount 是否存在
2. 验证 fromAccount 是否密码正确
3. 验证当前账户余额是否充足
4. 验证 toAccount 是否存在
5. 减少 fromAccount 的余额
6. 增加 toAccount 的余额
2. 验证 fromAccount 是否密码正确
3. 验证当前账户余额是否充足
4. 验证 toAccount 是否存在
5. 减少 fromAccount 的余额
6. 增加 toAccount 的余额
线程绑定连接
// 创建对象:当前线程绑定1个 Connection 类型对象
private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
// 当前线程从 ThreadLocal 里取,DBUtils.getConnection()
Connection connection = THREAD_LOCAL.get(); // 默认 get 到的是 null
if (connection == null) { // 如果为空
connection = DriverManager.getConnection(...); // properties获取三参
THREAD_LOCAL.set(connection);
}
Connection connection = THREAD_LOCAL.get(); // 默认 get 到的是 null
if (connection == null) { // 如果为空
connection = DriverManager.getConnection(...); // properties获取三参
THREAD_LOCAL.set(connection);
}
// 关闭连接资源,同时移除 ThreadLocal 对象,DBUtils.closeAll(c, s, r)
if (connection != null) {
connection.close();
THREAD_LOCAL.remove(); // 最后关闭 connection 的时候移除线程对象
}
// 调用时机:事务完成后的 finally 中(DAO层不关闭 connection)
DBUtils.closeAll(connection, null, null);
if (connection != null) {
connection.close();
THREAD_LOCAL.remove(); // 最后关闭 connection 的时候移除线程对象
}
// 调用时机:事务完成后的 finally 中(DAO层不关闭 connection)
DBUtils.closeAll(connection, null, null);
转账事务核心
Connection connection = null;
// ① 建立了一个数据库连接(线程已绑定)
connection = DBUtils.getConnection();
connection = DBUtils.getConnection();
// ② 开启事务:关闭自动提交
connection.setAutoCommit(false);
connection.setAutoCommit(false);
/* ... 业务中的原子操作,如转账中的余额扣除、余额增加 ... */
// ③ 提交事务:执行到这里无异常
connection.commit();
connection.commit();
} catch (...) {
// ④ 回滚事务:如果出现了异常
if (connection != null) {
connection.rollback();
}
} finally {
DBUtils.closeAll(connection, null, null);
}
// ④ 回滚事务:如果出现了异常
if (connection != null) {
connection.rollback();
}
} finally {
DBUtils.closeAll(connection, null, null);
}
普适性泛型工具类
封装DML方法:public int commonsUpdate(String sql, Object... args)
封装DQL方法:public List<T> commonsSelect(String sql, RowMapper<T> rowMapper, Object... args)
三层架构设计
表示层
view/
c: TestXxxxView
命名:xxxVIew
职责:收集用户的数据和需求、展示数据
职责:收集用户的数据和需求、展示数据
业务层
service/
i: XxxxService
impl/
c: XxxxServiceImpl
命名:XXXServiceImpl
职责:数据的加工处理、调用Dao组合完成业务实现、控制事务
职责:数据的加工处理、调用Dao组合完成业务实现、控制事务
DAO层
dao/
i: XxxxDao
impl/
c: XxxxDaoImpl
命名:xxxDaoImpl
职责:向业务层提供数据,将业务层加工处理后的数据同步到数据库
职责:向业务层提供数据,将业务层加工处理后的数据同步到数据库
实体类
entity/
c: Xxxx
工具类
utils/
c: DBUtils
c: DateUtils
Apache的DBUtils
介绍
Commons DbUtils 是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,
使用它能勾简化JDBC应用程序的开发!同时,不会影响程序的性能。
使用它能勾简化JDBC应用程序的开发!同时,不会影响程序的性能。
DbUtils是Java编程中数据库操作实用小工具,小巧、简单、实用。
对于数据表的查询操作,可以吧结果转换为List、Array、Set等集合。
便于操作对于数据表的DML操作,也变得很简单(只需要写SQL语句)。
对于数据表的查询操作,可以吧结果转换为List、Array、Set等集合。
便于操作对于数据表的DML操作,也变得很简单(只需要写SQL语句)。
接口/类
ResultSetHandler 接口:转换类型接口
BeanHandler 类:实现类,把一条记录转换成对象
BeanListHandler 类:实现类,把多条记录转换成List集合。
ScalarHandler 类:实现类,适合获取一行一列的数据。
BeanHandler 类:实现类,把一条记录转换成对象
BeanListHandler 类:实现类,把多条记录转换成List集合。
ScalarHandler 类:实现类,适合获取一行一列的数据。
QueryRunner:执行sql语句的类
增、删、改:update();
查询:query();
增、删、改:update();
查询:query();
使用步骤
① jar包:mysql-connector-java-5.1.25-bin.jar
② jar包:druid-1.1.5.jar
③ jar包:commons-dbutils-1.6.jar
④ database.properties配置文件
② jar包:druid-1.1.5.jar
③ jar包:commons-dbutils-1.6.jar
④ database.properties配置文件
开发步骤
// DBUtils中静态属性:null
private static DruidDataSource dataSource = null;
private static DruidDataSource dataSource = null;
// DBUtils中静态代码块:创建Druid德鲁伊 dataSource 连接池对象
static {
// ... database.properties
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
}
static {
// ... database.properties
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
}
// DBUtils中静态方法:返回一个数据源
public static DataSource getDataSource() {
return dataSource;
}
public static DataSource getDataSource() {
return dataSource;
}
// DAO实现类中调用方式
// 1.创建 QueryRunner 对象,并传递一个数据源对象
private QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());
// 2.使用 queryRunner 对象,DML-增删改使用 .update(); DQL-查询使用 .query();
Object[] params = {xxx.getXx()...}; // 对应占位符获取值
return queryRunner.update("insert into xxx(yyy...) values(?,?,?...)", params);
return queryRunner.query("select * from xxx where id = ?", new BeanHandler<[Xxx]>(Xxx.class), id);
return queryRunner.query("select * from user", new BeanListHandler<[Xxx]>(Xxx.class));
// 1.创建 QueryRunner 对象,并传递一个数据源对象
private QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());
// 2.使用 queryRunner 对象,DML-增删改使用 .update(); DQL-查询使用 .query();
Object[] params = {xxx.getXx()...}; // 对应占位符获取值
return queryRunner.update("insert into xxx(yyy...) values(?,?,?...)", params);
return queryRunner.query("select * from xxx where id = ?", new BeanHandler<[Xxx]>(Xxx.class), id);
return queryRunner.query("select * from user", new BeanListHandler<[Xxx]>(Xxx.class));
Demo
DBUtils.java
ThreadLocal 线程绑定当前使用的线程池中 connection 对象,
即可正确对事务进行开启、提交、回滚时操作的是同一个数据库连接!
即可正确对事务进行开启、提交、回滚时操作的是同一个数据库连接!
XxxxDaoImpl
database.properties
# 数据库配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/account?useUnicode=true&characterEncoding=utf8
username=root
password=123456
# 初始化连接数
initialSize=10
# 最大连接数
maxActive=30
# 最小空闲连接数
minIdle=5
# 超时等待时间,单位:毫秒ms
maxWait=5000
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/account?useUnicode=true&characterEncoding=utf8
username=root
password=123456
# 初始化连接数
initialSize=10
# 最大连接数
maxActive=30
# 最小空闲连接数
minIdle=5
# 超时等待时间,单位:毫秒ms
maxWait=5000
druid配置文件
database.properties
# 数据库配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8
username=root
password=123456
# 初始化连接数
initialSize=10
# 最大连接数
maxActive=30
# 最小空闲连接数
minIdle=5
# 超时等待时间,单位:毫秒ms
maxWait=5000
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8
username=root
password=123456
# 初始化连接数
initialSize=10
# 最大连接数
maxActive=30
# 最小空闲连接数
minIdle=5
# 超时等待时间,单位:毫秒ms
maxWait=5000
c3p0配置文件
c3p0.properties
# 数据库配置
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/db
c3p0.user=root
c3p0.password=123456
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/db
c3p0.user=root
c3p0.password=123456
HTML
简介
概述:HTML,Hyper Text Markup Language(超文本标记语言)
浏览器解析HTML标记的内容
浏览器解析HTML标记的内容
特点:简易性、可扩展性、平台无关性、通用性
发展:HTML2.0 >> 3.2 >> 4.0 >> 4.01 >> 5
基本结构
<!DOCTYPE html> <!-- 文档声明,告诉浏览器使用html解析 -->
<html> <!-- 页面标记 -->
<head> <!-- 网页头部 -->
<meta charset="utf-8" /> <!-- 字符集编码 -->
<title>我的页面</title> <!-- 页面标签标题 -->
</head>
<body> <!-- 网页主体,显示的部分 -->
第一个页面!
</body>
</html>
<html> <!-- 页面标记 -->
<head> <!-- 网页头部 -->
<meta charset="utf-8" /> <!-- 字符集编码 -->
<title>我的页面</title> <!-- 页面标签标题 -->
</head>
<body> <!-- 网页主体,显示的部分 -->
第一个页面!
</body>
</html>
1. HTML页面包含头部 head 和主体 body
2. HTML标签通常成对出现,有开始标签、结束标签称为 对标签;没有结束标签的为 空标签
3. HTML标签都有属性,格式:属性名="属性值" (多个属性名用空格间隔)
4. HTML不区分大小写,建议小写
5. HTML文件后缀名为 .html / .htm
2. HTML标签通常成对出现,有开始标签、结束标签称为 对标签;没有结束标签的为 空标签
3. HTML标签都有属性,格式:属性名="属性值" (多个属性名用空格间隔)
4. HTML不区分大小写,建议小写
5. HTML文件后缀名为 .html / .htm
基本标签
结构标签
根
<html> </html>
头
<head> </head>
标题
<title> </title> 在头标签中
元信息
<meta charset="utf8"> 在头标签中
主体
<body> </body>
属性
color="颜色"
bgcolor="背景色"
background="背景图路径"
颜色表示方式:① 颜色名称 red green ② RGB模式 #000000 #FFFFFF
bgcolor="背景色"
background="背景图路径"
颜色表示方式:① 颜色名称 red green ② RGB模式 #000000 #FFFFFF
排版标签
注释
<!-- 注释文本 -->
换行
<br />
段落
<p> </p> 自带换行,有行间距
属性
align="文本对齐方式 left 默认、center、right"
水平线
<hr />
属性
width="宽度" 像素px / 百分比%
size="高度" 水平线的粗细,避免过粗,一般个位数,eg:6px
color="水平线颜色"
align="对齐方式 left、center默认、right"
size="高度" 水平线的粗细,避免过粗,一般个位数,eg:6px
color="水平线颜色"
align="对齐方式 left、center默认、right"
标题标签
<h1>一级标题</h1> 数字越小
<h2>二级标题</h2> 字号越大
<h3>三级标题</h3> 默认加粗
<h4>四级标题</h4> 默认字号
<h5>五级标题</h5> 默认占据一行
<h6>六级标题</h6> 默认有行间距
<h2>二级标题</h2> 字号越大
<h3>三级标题</h3> 默认加粗
<h4>四级标题</h4> 默认字号
<h5>五级标题</h5> 默认占据一行
<h6>六级标题</h6> 默认有行间距
容器标签
块标签
<div> </div> 独占一行,自带换行
默认宽度为浏览器部分宽度,高度会跟随元素内的文本内容而改变
应用:结合css做页面分块,布局
默认宽度为浏览器部分宽度,高度会跟随元素内的文本内容而改变
应用:结合css做页面分块,布局
行级标签
<span> </span> 所有内容都在同一行
默认宽度和高度都会随着内容改变
应用:友好提示信息的显示
默认宽度和高度都会随着内容改变
应用:友好提示信息的显示
列表标签
无序列表
<ul>
<li> </li>
<li> </li>
<li> </li>
</ul>
<li> </li>
<li> </li>
<li> </li>
</ul>
type="?"
实心圆:disc (默认)
空心圆:circle
黑色方块:square
实心圆:disc (默认)
空心圆:circle
黑色方块:square
有序列表
<ol>
<li> </li>
<li> </li>
<li> </li>
</ol>
<li> </li>
<li> </li>
<li> </li>
</ol>
type="?"
数字:1
大小写字母:A / a
罗马数字:I / i
数字:1
大小写字母:A / a
罗马数字:I / i
定义列表
<dl> 列表
<dt>Coffee</dt> 标题
<dd>Black hot drink</dd> 内容
<dt>Milk</dt>
<dd>White cold drink</dd>
</dl>
<dt>Coffee</dt> 标题
<dd>Black hot drink</dd> 内容
<dt>Milk</dt>
<dd>White cold drink</dd>
</dl>
列表嵌套
可以相互任意嵌套
图片标签
<img />
属性
src="图片地址"
height="高度"
width="宽度"
border="边框"
alt="图片未被加载时的提示文字"
title="图片被鼠标悬停时的提示文字"
height="高度"
width="宽度"
border="边框"
alt="图片未被加载时的提示文字"
title="图片被鼠标悬停时的提示文字"
链接标签
<a> 文本或图片 </a>
属性
href="跳转的地址" // 跳转外网需要添加协议http/https
target="_self"(当前页) "_blank"(一直新页面) "_search"(仅1个新页面复用)
target="_self"(当前页) "_blank"(一直新页面) "_search"(仅1个新页面复用)
充当锚点(跳转顶部/跳转底部)
提供率 name 属性,为其赋值
点击跳转的标签 href 属性给 #name
<a name="tops"></a>
<a href="#tops">跳到顶部</a>
提供率 name 属性,为其赋值
点击跳转的标签 href 属性给 #name
<a name="tops"></a>
<a href="#tops">跳到顶部</a>
表格标签
<table border="1"> 表格
<tr>
<th>header</th>
<th>header</th>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
</tr>
</table>
<tr>
<th>header</th>
<th>header</th>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
</tr>
</table>
属性
table
width="表格宽度"
height="表格高度"
border="边框宽度"
bordercolor="边框颜色"
cellspacing="单元格之间的间距"
cellpadding="单元格与内容的间距"
align="对齐方式 left center right" 表格相对于页面
height="表格高度"
border="边框宽度"
bordercolor="边框颜色"
cellspacing="单元格之间的间距"
cellpadding="单元格与内容的间距"
align="对齐方式 left center right" 表格相对于页面
th
表头,默认加粗、居中
td
align="对齐方式 left center right" 内容相对于单元格
valign="对齐方式 top middle bottom" 内容相对于单元格
valign="对齐方式 top middle bottom" 内容相对于单元格
列合并
colspan="横跨的列数"
行合并
rowspan="纵跨的行数"
文本标签
普通的文字是这样
<b>b 粗体文字</b>
<strong>strong 加重文字</strong>
<big>big 大号文字</big>
<small>small 小号文字</small>
<em>em 着重文字</em>
<i>i 斜体文字</i>
sub 下标文字:CO<sub>2</sub>
sup 上标文字:注解<sup>[1]</sup>
<ins>ins 插入文字</ins>
<del>del 删除文字</del>
<b>b 粗体文字</b>
<strong>strong 加重文字</strong>
<big>big 大号文字</big>
<small>small 小号文字</small>
<em>em 着重文字</em>
<i>i 斜体文字</i>
sub 下标文字:CO<sub>2</sub>
sup 上标文字:注解<sup>[1]</sup>
<ins>ins 插入文字</ins>
<del>
表单标签
定义标签
<form> </form>
HTML表单用于搜集不同类型的用户输入信息。
输入标签
<input />
表单元素:
type 不同的输入方式
name 用于拼接到链接地址提交到服务器,格式:name1=value1&name2=value2
value 默认值
checked 单选选中
selected 多选选中
type 不同的输入方式
name 用于拼接到链接地址提交到服务器,格式:name1=value1&name2=value2
value 默认值
checked 单选选中
selected 多选选中
登陆界面
<input type="radio" name="sex" value="female" />女
<option value="zz" selected="selected">南阳</option>
</select>
<input type="checkbox" name="hobbys" value="football" checked="checked" />足球
<input type="checkbox" name="hobbys" value="volleyball" checked="checked" />排球
- 账户:<input type="text" name="username" placeholder="请输入账户" />
- 密码:<input type="password" name="password" placeholder="请输入密码" />
- 性别:
<input type="radio" name="sex" value="female" />女
- 照片:type="file"
- 地址:<select name="city">
<option value="zz" selected="selected">南阳</option>
</select>
- 爱好:
<input type="checkbox" name="hobbys" value="football" checked="checked" />足球
<input type="checkbox" name="hobbys" value="volleyball" checked="checked" />排球
- 介绍:<textarea name="introduce"></textarea>
- 提交:
<input type="submit" name="submit" value="注册" />
<button type="submit">注册</button> - 清空:
<input type="reset" name="reset" id="" value="清空" />
<button type="reset">清空</button>
框架标签
<frameset> </frameset> // 代替body标签
<frame> </frame> // 分割页面的内容,在frameset中
<frame> </frame> // 分割页面的内容,在frameset中
属性
frameset属性:
- row="20%,*" 横向20%+80%
- cols="50%,*" 纵向50%+50%
frame属性:
- src="填充的内容"
- noresize="noresize" 不能改变大小
- scrolling="no" 不显示滚动条
- 定位到具体位置使用 name 属性
Demo
其他标签
标签
<!-- 网页的编码 -->
<meta charset="utf-8">
<!-- 网页的编码:html 4.01 -->
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<!-- 网页的关键字 seo -->
<meta name="keywords" content="关键词1,关键词2,关键词3"/>
<!-- 网页的描述 seo -->
<meta name="description" content="this is my page"/>
<!-- 页面自动跳转,2秒后跳转百度 -->
<meta http-equiv="refresh" content="2;url=https://www.baidu.com"/>
<!-- href: 引入css文件地址 -->
<link rel="stylesheet" type="text/css" href="css/01CSS.css"/>
<!-- src: js文件地址 -->
<script src="js文件地址" type="text/javascript"></script>
<meta charset="utf-8">
<!-- 网页的编码:html 4.01 -->
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<!-- 网页的关键字 seo -->
<meta name="keywords" content="关键词1,关键词2,关键词3"/>
<!-- 网页的描述 seo -->
<meta name="description" content="this is my page"/>
<!-- 页面自动跳转,2秒后跳转百度 -->
<meta http-equiv="refresh" content="2;url=https://www.baidu.com"/>
<!-- href: 引入css文件地址 -->
<link rel="stylesheet" type="text/css" href="css/01CSS.css"/>
<!-- src: js文件地址 -->
<script src="js文件地址" type="text/javascript"></script>
符号
- < 小于号 <
- > 大于号 >
- & 与字符 &
- " 引号 "
- ® 已注册 ®
- © 版权©
- ™ 商标™
- 空格
¥ 人民币 ¥
CSS
标签/属性
<style>
选择器{
属性名:属性值;
}
</style>
选择器{
属性名:属性值;
}
</style>
<xxx style="aaa:AAA; bbb:BBB;">
CSS使用方式
内联方式
<font style="color: red;">这是一行字</font>
标签内,单独对特定标签元素生效,简单,但不能复用。
内部方式
<style type="text/css">
font{
font-size: 50px;
color: darkblue;
}
a{ text-decoration:none }
</style>
</head>
font{
font-size: 50px;
color: darkblue;
}
a{ text-decoration:none }
</style>
</head>
- 在 head 标签中,使用 style 标签
- 使用选择器选中元素
- 编写 css 代码
外部方式
<link rel="stylesheet" type="text/css" href="./css/01CSS.css"/>
- 新建一个 css 样式文件
- 编写 css 代码
- 在 html 文件中引入 css 外部文件,使用 link 标签引入
CSS选择器
标签选择器
标签名{
属性名:属性值;
}
属性名:属性值;
}
body全局样式:标签名使用body
id选择器
id="aaa"
#id选择器{
属性名:属性值;
}
属性名:属性值;
}
类选择器
class="aaa"
.类选择器{
属性名:属性值;
}
属性名:属性值;
}
属性选择器
标签名[属性名]{
属性名:属性值;
}
属性名:属性值;
}
标签名[属性名="值"]{
属性名:属性值;
}
属性名:属性值;
}
eg:
a[href^="http"] { 样式 } 以http开头的
a[href$="cn"] { 样式 } 以cn结尾的
a[href*="u"] { 样式 } 包含了字符u的
a[href^="http"] { 样式 } 以http开头的
a[href$="cn"] { 样式 } 以cn结尾的
a[href*="u"] { 样式 } 包含了字符u的
层级选择器
父选择器 子选择器{
属性名:属性值;
}
//【后代】会跨子标签层级
属性名:属性值;
}
//【后代】会跨子标签层级
父选择器>子选择器{
属性名:属性值;
}
// 【子代】亲儿子不跨标签层级
属性名:属性值;
}
// 【子代】亲儿子不跨标签层级
A选择器+B选择器{
属性名:属性值;
}
// 【相邻兄弟】自身之后的1个兄弟标签
属性名:属性值;
}
// 【相邻兄弟】自身之后的1个兄弟标签
A选择器~B选择器{
属性名:属性值;
}
// 【通用兄弟】自身之后的所有兄弟标签
属性名:属性值;
}
// 【通用兄弟】自身之后的所有兄弟标签
在结构中有标签包裹父子/相邻层级关系时使用。
分组选择器
#id选择器, .类选择器, 标签名{
属性名:属性值;
}
属性名:属性值;
}
逗号分隔不同的选择器,将这些划分为一组,使用共同的样式
不同的选择器不同的样式做修改,样式会叠加。
不同的选择器相同的样式做修改,遵循优先级:
优先级(范围越小优先级越高):内联样式 > id > class > 标签
不同的选择器相同的样式做修改,遵循优先级:
优先级(范围越小优先级越高):内联样式 > id > class > 标签
CSS伪类
用于向某些选择器添加特殊的效果。
锚伪类
- * 主要用于 a 标签上
a:link {color: #FF0000} /* 未访问的链接样式 */ - a:visited {color: #00FF00} /* 已访问的链接样式 */
- a:hover {color: #FF00FF} /* 鼠标移动到标签内容上 */
- a:active {color: #0000FF} /* 选定时标签内容样式 */
注意:在 CSS 定义中,a:hover 必须被置于 a:link 和 a:visited 之后,才是有效的。
注意:在 CSS 定义中,a:active 必须被置于 a:hover 之后,才是有效的。
注意:伪类名称对大小写不敏感。
注意:在 CSS 定义中,a:active 必须被置于 a:hover 之后,才是有效的。
注意:伪类名称对大小写不敏感。
CSS属性
字体
定义文本的字体系列、大小、加粗、风格(如斜体)和变形(如小型大写字母)
属性
- font 简写属性。作用是把所有针对字体的属性设置在一个声明中。eg:font:oblique 700 30px "黑体"; /* 样式 加粗 大小 风格 */
- font-family 设置字体系列。
- font-size 设置字体的尺寸。
- font-style 设置字体风格。(斜体)
- font-weight 设置字体的粗细。
文本
改变文本的颜色、字符间距,对齐文本,装饰文本,对文本进行缩进,等等
属性
- color 设置文本颜色
- direction 设置文本方向。
- line-height 设置行高。
- text-align 对齐元素中的文本。(左对齐、居中、右对齐)
- text-decoration 向文本添加修饰。(上划线、下划线、删除线、无线条)
- text-indent 缩进元素中文本的首行(2em : 2个字符;20% : 20%的宽度)
- text-transform 控制元素中的字母。(全大写、全小写、所有单词首字母大写)
- unicode-bidi 设置文本方向。
- white-space 设置元素中空白的处理方式。(="nowrap" 禁止文本分行,即都在1行内)
- letter-spacing 设置字符间距。
- word-spacing 设置单词间距。
背景
repeat-x:只在水平方向都平铺
repeat:在水平垂直方向都平铺
no-repeat:任何方向都不平铺
background: red center no-repeat url(img/003.jpg);
- background-color:设置背景颜色,默认透明
- background-image:url("图片路径");设置背景图片
background-size: 设置背景图片的尺寸属性 - background-repeat:
repeat-x:只在水平方向都平铺
repeat:在水平垂直方向都平铺
no-repeat:任何方向都不平铺
- background-position: 改变图像在背景中的位置。top、bottom、left、right 和 center(1个位置值或多个组合位置值)
background: red center no-repeat url(img/003.jpg);
列表
list-style: decimal url(img/001.png) inside;
去掉样式:
list-style:none;
list-style-type:none;
- list-style-type:decimal;改变列表的标志类型
- list-style-image: url("images/dog.gif");用图像表示标志
- list-style-position: inside;确定标志出现在列表项内容之外还是内容内部
list-style: decimal url(img/001.png) inside;
去掉样式:
list-style:none;
list-style-type:none;
显示
block 块级元素
inline 行内元素
inline-block 行内块级元素
align-items: center; 垂直居中
justify-content: center; 水平居中
- display:
block 块级元素
inline 行内元素
inline-block 行内块级元素
- display:flex 伸缩布局:
align-items: center; 垂直居中
justify-content: center; 水平居中
轮廓
轮廓(outline)
绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。常用属性:
绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。常用属性:
- outline-style:
- outline-color:red; 设置轮廓的颜色
- outline-width:10px 设置轮廓的宽度
浮动
* 浮动起来的元素会遮盖没有浮动属性的元素
right 右侧不允许浮动元素
both 左右两侧均不允许浮动元素
none 默认,允许浮动元素出现在两侧
inherit 继承父元素
- float="?"
* 浮动起来的元素会遮盖没有浮动属性的元素
- clear="?"
right 右侧不允许浮动元素
both 左右两侧均不允许浮动元素
none 默认,允许浮动元素出现在两侧
inherit 继承父元素
定位
relative(相对定位) 相对自身原来的位置偏移某个距离,原本所占的空间仍然保留。
absolute(绝对定位) 相对于已定位的父元素进行偏移某个距离,不保留原空间。(如无已定位的父元素则相对于浏览器)
fixed(固定定位) 固定加载位置,不会因为滚动而变化位置
left - 相对浏览器左边
right - 相对浏览器右边
top - 相对浏览器顶端
bottom - 相对浏览器底端
- position:
relative(相对定位) 相对自身原来的位置偏移某个距离,原本所占的空间仍然保留。
absolute(绝对定位) 相对于已定位的父元素进行偏移某个距离,不保留原空间。(如无已定位的父元素则相对于浏览器)
fixed(固定定位) 固定加载位置,不会因为滚动而变化位置
left - 相对浏览器左边
right - 相对浏览器右边
top - 相对浏览器顶端
bottom - 相对浏览器底端
注意:body有默认的margin(8px)
CSS盒子
尺寸
- width:设置元素的宽度
- height:设置元素的高度
- line-height:设置元素的行高
边框
border
double:空心线
dashed:虚线组成的边框
dotted:圆点组成的边框
border: 1px solid red;
- border-style:边框样式,值有以下情况:
double:空心线
dashed:虚线组成的边框
dotted:圆点组成的边框
- border-color:边框颜色
- border-width:边框宽度
border: 1px solid red;
外边距
margin-top:像素值px;
margin-bottom:像素值px;
margin-left:像素值px;
margin-right:像素值px;
- margin:外间距,边框和边框外层元素的距离
margin-top:像素值px;
margin-bottom:像素值px;
margin-left:像素值px;
margin-right:像素值px;
内边距
padding-right:像素值px;
padding-top:像素值px;
padding-bottom:像素值px;
- padding:内间距,元素内容和边框之间的距离((top right bottom left))
padding-right:像素值px;
padding-top:像素值px;
padding-bottom:像素值px;
实际
盒子模型的实际的宽度:width+2*(padding+border+margin)
盒子模型的实际的高度:height+2*(padding+border+margin)
盒子模型的实际的高度:height+2*(padding+border+margin)
CSS3扩展属性
圆角
border-radius:50%; //圆角半径
可以将正方形图片切为圆形。
可以将正方形图片切为圆形。
阴影
相对于自身原来的位置偏移x,y像素值 模糊半径值 颜色值
box-shadow:10px 10px 5px #888888; //方框阴影属性
text-shadow:5px 5px 5px #ffff00; //文本阴影属性
box-shadow:10px 10px 5px #888888; //方框阴影属性
text-shadow:5px 5px 5px #ffff00; //文本阴影属性
背景图片尺寸
<body style="text-align: center;
background:url(img/1.png);
background-size: 200px 300px;
background-repeat: no-repeat;">
</body> //背景图片尺寸,不平铺
background:url(img/1.png);
background-size: 200px 300px;
background-repeat: no-repeat;">
</body> //背景图片尺寸,不平铺
多个背景图片
background-image:url(bg_flower.gif),url(bg_flower_2.gif);
Tomcat
基本概念
C/S模式:Client/Server模式(客户端/服务器)【优】客户端分担了负载【劣】新功能必须需要重新下载
B/S模式:Browser/Server模式(浏览器/服务器) 【优】使用简单只需要浏览器【劣】负载都交给了服务器
B/S模式:Browser/Server模式(浏览器/服务器) 【优】使用简单只需要浏览器【劣】负载都交给了服务器
Tomcat,是Apache-Jarkarta开源项目中的一个子项目,小型、轻量级的支持JSP和Servlet技术的web服务器。
最新的Servlet和JSP规范因为有 Sun 公司的参与和支持总能得到体现,技术先进、性能稳定、免费!
最新的Servlet和JSP规范因为有 Sun 公司的参与和支持总能得到体现,技术先进、性能稳定、免费!
web动态项目比web静态项目区别:
动态资源中可以有静态资源,可以有动态资源,必须有 WEB_INF 目录 和 WEB_INF/web.xml 文件。
动态资源中可以有静态资源,可以有动态资源,必须有 WEB_INF 目录 和 WEB_INF/web.xml 文件。
Tomcat配置
Tomcat服务器搭建
安装
1.官网下载 tomcat.apache.org Tomcat8.0|8.5版本
2.解压到一个没有特殊符号的路径
3.进入到解压的目录下,bin\startup.bat启动
* 不要放入层次多的文件夹中、不建议放中文路径、依赖JAVA_HOME环境变量。
2.解压到一个没有特殊符号的路径
3.进入到解压的目录下,bin\startup.bat启动
* 不要放入层次多的文件夹中、不建议放中文路径、依赖JAVA_HOME环境变量。
目录
tomcatusers.xml 存储tomcat用户信息
web.xml 部署描述符文件,注册了很多MIME即文档类型
context.xml 对所有应用的统一配置,通常不配置它
- bin 二进制可执行文件和启动脚本文件
- conf 配置目录:
tomcatusers.xml 存储tomcat用户信息
web.xml 部署描述符文件,注册了很多MIME即文档类型
context.xml 对所有应用的统一配置,通常不配置它
- lib 服务器启动以来的核心类库,jar包文件
- logs 日志文件,启动、关闭、错误、异常等信息
- temp 存放临时文件,可以在tomcat关闭后删除
- webapps 存放web项目的核心目录,其中每个文件夹都是一个项目,ROOT是未给出项目目录时的特殊项目
- work 运行时生成的文件,最终运行的文件都在这里,通过webapps中的项目生成的
启动
bin/startup.bat 启动服务器
bin/shutdown.bat 关闭服务器
bin/shutdown.bat 关闭服务器
* 中文乱码解决:logging.properties >> 注释掉line47 #java.util.logging.ConsoleHandler.encoding = UTF-8
访问
http://ip:port/project/资源 (静态[html/css/javascript]、动态[servlet/jsp])
浏览器访问 http://localhost:8080 或 http://127.0.0.1:8080
默认访问 index.xml 或 index.jsp
原因:Tomcat目录 conf 目录下 web.xml 规定了默认欢迎页面
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
自定义的 web 项目也部署到 tomcat 中,也会遵守该规定。
常见错误
404:无法找到文件
500:内部服务器错误
500:内部服务器错误
配置
配置默认访问页
直接修改 tomcat 的 web.xml 中的 <welcome-file-list> 会影响到所有项目的欢迎页面。
在项目目录中 WEB_INF/web.xml 中修改 <welcome-file-list> 仅针对当前项目有效。
配置端口号:conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" /> //默认8080
connectionTimeout="20000"
redirectPort="8443" /> //默认8080
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" /> //遵循浏览器默认端口可以直接用 http://localhost 访问
connectionTimeout="20000"
redirectPort="8443" /> //遵循浏览器默认端口可以直接用 http://localhost 访问
配置项目为默认启动项目:conf/server.xml
重命名 ROOT 项目或删除该目录
</Host>前 新增如下内容:
<Context docBase="磁盘绝对路径" path="" debug="0" reloadable="true"/>
<Context docBase="磁盘绝对路径" path="" debug="0" reloadable="true"/>
B/S数据流程图
Tomcat项目部署
直接将项目放到webapps目录
直接拷贝
配置虚拟项目目录
conf/server.xml
<Host>
...
<Context docBase="磁盘路径" path="/访问名称" />
</Host>
...
<Context docBase="磁盘路径" path="/访问名称" />
</Host>
访问 http://localhost:8080/访问名称/资源文件
配置虚拟项目目录优化版
conf/Catalina/localhost
新建 projname.xml
编辑
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="磁盘路径" />
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="磁盘路径" />
访问 http://localhost:8080/projname/资源文件
Tomcat在开发工具支持
Eclipse中集成Tomcat
Window >> Preferences >> Server
点击add >> 选择对应的版本 >> Finish
Intellij IDEA中集成Tomcat
File >> Settings >> build-execution-deployment >> 选择Application Servers >> 添加Tomcat >> 选择Tomcat安装根目录
如:D:\tomcat\apache-tomcat-8.5.53
如:D:\tomcat\apache-tomcat-8.5.53
* 解决源码编译运行后打印中文乱码问题:Tomcat-8.5.53 >> Edit Configuration >> VM option:-Dfile.encoding=utf-8
自定义Tomcat服务器
@注解
注解Annotation用于描述元数据的修饰符,包括类、成员变量、构造方法、成员方法、方法参数和声明。
JDK5.0之后引入的特性。
JDK5.0之后引入的特性。
注解分类
类型
标记注解:注解中没有属性可以设置,如 @Override、@Deprecated
单值注解:注解中只有一个属性("value="可省略),如 @SuppressWarings{ String[] value; }
完整注解:注解中有多个属性
单值注解:注解中只有一个属性("value="可省略),如 @SuppressWarings{ String[] value; }
完整注解:注解中有多个属性
来源
Java内置注解
@Override
方法覆盖注解
方法覆盖注解
判断子类中的方法是否是一个父类方法的重写方法
@Deprecated
过时标记注解
过时标记注解
标记一个类/方法/变量是否是过时的,调用时会有删除线
@SupressWarning("all")
压制所有警告注解
压制所有警告注解
可以消除编译器/开发工具对警告的提示
@FunctionaInterface
函数式接口注解
函数式接口注解
标记只能有1个公开抽象方法,用于Lambda简写
@SafeVarargs
安全的可变参数注解
安全的可变参数注解
帮助检查可变参数与泛型结合时的使用情况
第三方注解
Junit
@Test
单元测试注解
单元测试注解
import org.junit.Test;
* 该注解的方法被强制public且无参
* 可以直接运行@Test注解的方法,底层还是 main 方法运行,通过(反射+@Test注解)生效。
* 该注解的方法被强制public且无参
* 可以直接运行@Test注解的方法,底层还是 main 方法运行,通过(反射+@Test注解)生效。
其他待补充
Servlet
@WebServlet
web资源配置注解
web资源配置注解
Servlet3.0+版本支持,可以替代web.xml配置。
(框架注解)待补充
自定义注解
@Retention(RetentionPolicy.RUNTIME)
public @interface 自定义注解名 {
数据类型 属性名1() default 默认值1;
数据类型 属性名2() default 默认值2;
数据类型 属性名3()[] default {元素值1, 元素值2, ...};
}
public @interface 自定义注解名 {
数据类型 属性名1() default 默认值1;
数据类型 属性名2() default 默认值2;
数据类型 属性名3()[] default {元素值1, 元素值2, ...};
}
Demo
元注解
定义在自定义注解上,规定自定义的作用区域、存活策略。
@Target
规定自定义注解的作用区域
规定自定义注解的作用区域
public @interface Target {
ElementType[] value();
}
ElementType[] value();
}
当前定义的注解可以应用的范围:
- TYPE, 类、接口、枚举的类型定义上
- FIELD, 成员变量上
- METHOD, 成员方法上
- PARAMETER, 方法参数上
- CONSTRUCTOR, 构造方法上
- LOCAL_VARIABLE, 局部变量上
- ANNOTATION_TYPE, 注解类型上
- PACKAGE, 包定义语句上
- TYPE_PARAMETER, 类型参数声明
- TYPE_USE, 使用一个类型
@Retention
规定自定义注解的存活策略
规定自定义注解的存活策略
public @interface Retention {
RetentionPolicy value();
}
RetentionPolicy value();
}
当前定义的注解可以存活的方式:
- SOURCE, 仅仅停留在源码中,编译时即除去
- CLASS, 保留到编译后的字节码中,运行时无法获取注解信息
- RUNTIME, 保留到运行时,通过反射机制可以获取注解信息
@Documented
文档标记注解(无参数)
文档标记注解(无参数)
将注解中的内容包含到Javadoc中。
@Inherited
可随修饰类被继承的标记注解(无参数)
可随修饰类被继承的标记注解(无参数)
例如B继承了A,A添加了注解,那么B也会继承同样的注解。
获取注解信息
核心步骤
反射机制
① 注解在类/方法上,获取对应的 Class 对象 / Method 对象
② 判断类/方法上的注解是否存在 .isAnnotationPresent(注解名.class)
③ 获取注解信息 .getAnnotation(注解名.class)
① 注解在类/方法上,获取对应的 Class 对象 / Method 对象
② 判断类/方法上的注解是否存在 .isAnnotationPresent(注解名.class)
③ 获取注解信息 .getAnnotation(注解名.class)
自定义注解@MyTest
步骤:
1.自定义注解
2.在测试类上使用该自定义注解
3.让自定义注解生效
● 获取测试类的Class对象
● 获取测试类的成员方法
● 判断方法上是否有自定义注解
● 执行添加了注解的方法
1.自定义注解
2.在测试类上使用该自定义注解
3.让自定义注解生效
● 获取测试类的Class对象
● 获取测试类的成员方法
● 判断方法上是否有自定义注解
● 执行添加了注解的方法
Demo
自定义注解@JDBCInfo
步骤:
1.自定义注解@JDBCInfo
2.在DBUtils工具类上使用@JDBCInfo
3.在DBUtils工具类的静态代码中获取注解中的属性(反射读取注解信息)
1.自定义注解@JDBCInfo
2.在DBUtils工具类上使用@JDBCInfo
3.在DBUtils工具类的静态代码中获取注解中的属性(反射读取注解信息)
Class<DBUtils> dbClass = DBUtils.class;
boolean present = dbClass.isAnnotationPresent(JDBCInfo.class);
if (present) {
JDBCInfo jdbcInfo = dbClass.getAnnotation(JDBCInfo.class);
DRIVERCLASS = jdbcInfo.driverClass();
...
}
boolean present = dbClass.isAnnotationPresent(JDBCInfo.class);
if (present) {
JDBCInfo jdbcInfo = dbClass.getAnnotation(JDBCInfo.class);
DRIVERCLASS = jdbcInfo.driverClass();
...
}
@JDBCInfo
DBUtils
TestJDBCInfo
注解+反射+设计模式【日志记录】
装饰者模式
装饰类中调用所有方法,并定义printLog()方法增加日志信息:
1.获取UserDao实现子类的 Class 对象
2.获取UserDao接口的 Class 对象
3.获取到接口中对应的方法
4.判断方法上是否有注解信息
5.有注解,则获取注解信息
6.拼接日志需要的时间和必要信息
1.获取UserDao实现子类的 Class 对象
2.获取UserDao接口的 Class 对象
3.获取到接口中对应的方法
4.判断方法上是否有注解信息
5.有注解,则获取注解信息
6.拼接日志需要的时间和必要信息
动态代理模式
动态代理的匿名内部类参数中定义增强日志信息的逻辑:
1.检查方法上是否有对应注解
2.有注解:执行原有功能,打印日志
3.拼接日志需要的时间和必要信息
4.没注解:执行原有功能
1.检查方法上是否有对应注解
2.有注解:执行原有功能,打印日志
3.拼接日志需要的时间和必要信息
4.没注解:执行原有功能
@SysLog
UserDao接口
UserDaoImpl实现类
装饰者设计模式:UserDaoWrapper装饰类
测试类验证
动态代理设计模式:测试类 Proxy.newProxyInstance(...) 验证
xml与注解-对比
xml
优点:
1、降低耦合,使容易扩展
2、对象之间的关系一目了然
3、xml配置文件比注解功能齐全
缺点:
1、配置文件配置工作量相对注解要大
1、降低耦合,使容易扩展
2、对象之间的关系一目了然
3、xml配置文件比注解功能齐全
缺点:
1、配置文件配置工作量相对注解要大
注解
优点:
1、在class文件中,可以降低维护成本
2、提高开发效率
缺点:
1、如果对注解文件(Annotation)进行修改,需要重新编译整个工程
2、业务类之间的关系不如xml配置那样一目了然
3、程序中过多的注解,对于代码的简洁度有一定影响
4、注解功能没有xml配置文件齐全
1、在class文件中,可以降低维护成本
2、提高开发效率
缺点:
1、如果对注解文件(Annotation)进行修改,需要重新编译整个工程
2、业务类之间的关系不如xml配置那样一目了然
3、程序中过多的注解,对于代码的简洁度有一定影响
4、注解功能没有xml配置文件齐全
* 大多数情况下使用配置文件,Spring Boot流行起来,就流行注解配置(注解开发)。
Servlet
Servlet基础
概念
Servlet 一个可以执行在服务器中的Java程序。
核心作用
1. 接收客户端浏览器请求,完成操作任务
2. 动态生成网页(页面数据可变)
3. 将包含操作结果的动态网页响应给客户端浏览器
2. 动态生成网页(页面数据可变)
3. 将包含操作结果的动态网页响应给客户端浏览器
目录结构
|--webapps(存放所有网站)
|--MyServlet(网站)
|--WEB_INF(核心内容)
|--classes/*.class(.class文件)
|--lib/*.jar(网站需要的jar包)
|--web.xml(配置文件)
|--css/*.css(样式文件)
|--img/*.jpg/png/bmg/gif(图片资源)
|--js/*.js(脚本文件)
|--*.html(静态页面)
|--XXXServlet
|--MyServlet(网站)
|--WEB_INF(核心内容)
|--classes/*.class(.class文件)
|--lib/*.jar(网站需要的jar包)
|--web.xml(配置文件)
|--css/*.css(样式文件)
|--img/*.jpg/png/bmg/gif(图片资源)
|--js/*.js(脚本文件)
|--*.html(静态页面)
|--XXXServlet
配置库包
External Library中没有Tomcat包( jsp-api.jar & servlet-api.jar)时:
Alt+1 切到项目窗口 >> F4 打开Module Setting >> 选择Dependencies >> 增加Tomcat的库
Alt+1 切到项目窗口 >> F4 打开Module Setting >> 选择Dependencies >> 增加Tomcat的库
开发步骤
创建目录结构
方式一:实现 javax.servlet.Servlet 接口,重写 5 个主要方法,处理请求的方法是 service( )——缺点:5个方法中只有1个方法有用
方式二:继承 javax.servlet.GenericServlet 抽象类,重写需要的方法,处理请求的方法是 service( )——缺点:与协议无关,无法满足http协议的web项目
方式三:继承 javax.servlet.http.HttpServlet 抽象类,默认重写了 service( ) 方法,且针对http协议优化,需自行重写 doGet( ) 和 doPost( ) 方法处理请求
方式二:继承 javax.servlet.GenericServlet 抽象类,重写需要的方法,处理请求的方法是 service( )——缺点:与协议无关,无法满足http协议的web项目
方式三:继承 javax.servlet.http.HttpServlet 抽象类,默认重写了 service( ) 方法,且针对http协议优化,需自行重写 doGet( ) 和 doPost( ) 方法处理请求
在文件 WEB_INF/web.xml 中新增如下内容
<servlet>
<servlet-name>Demo01</servlet-name>
<servlet-class>com.demo.t1.servlet.Demo01</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Demo01</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
<servlet-name>Demo01</servlet-name>
<servlet-class>com.demo.t1.servlet.Demo01</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Demo01</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
web项目中会有 /demo 的访问资源,访问方式: http://localhost:8080/projname/demo
Servlet配置
web.xml配置(Servlet所有版本支持)
为当前项目配置多个Servlet映射:
配置方式:可写多组 servlet 和 servlet-mapping 的标签,用来匹配映射不同的页面执行对应的不同的Servlet
为 Servlet 配置多个访问名称:
方式①:增加多对<servlet-mapping>标签,修改其中的 <url-pattern> 标签;
方式②:在<servlet-mapping>标签中,增加多对 <url-pattern> 标签。
配置方式:可写多组 servlet 和 servlet-mapping 的标签,用来匹配映射不同的页面执行对应的不同的Servlet
为 Servlet 配置多个访问名称:
方式①:增加多对<servlet-mapping>标签,修改其中的 <url-pattern> 标签;
方式②:在<servlet-mapping>标签中,增加多对 <url-pattern> 标签。
<url-pattern>匹配规则
精确匹配 /具体的名称 只有url路径是具体的名称的时候才会触发Servlet
后缀匹配 *.xxx 只要是xxx结尾的就匹配触发Servlet
目录匹配 /a/b/c* 匹配对应目录资源下所有请求,包含服务器的所有资源
通配匹配 / 匹配所有请求,包含服务器的所有资源,不包含.jsp——为缺省Servlet(Tomcat自带缺省)
后缀匹配 *.xxx 只要是xxx结尾的就匹配触发Servlet
目录匹配 /a/b/c* 匹配对应目录资源下所有请求,包含服务器的所有资源
通配匹配 / 匹配所有请求,包含服务器的所有资源,不包含.jsp——为缺省Servlet(Tomcat自带缺省)
<load-on-startup>加载Servlet
<load-on-startup>0</load-on-startup>
</servlet>
</servlet>
1) 标记容器是否在启动的时候就加载对应的 Servlet (实例化并调用其init()方法)
2) 它的值必须是一个整数,表示servlet应该被载入的顺序
3) 当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个 Servlet
4) 当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载
5) 正数的值越小,该servlet的优先级越高,应用启动时就越先加载
6) 当值相同时,容器就会自己选择顺序来加载
2) 它的值必须是一个整数,表示servlet应该被载入的顺序
3) 当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个 Servlet
4) 当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载
5) 正数的值越小,该servlet的优先级越高,应用启动时就越先加载
6) 当值相同时,容器就会自己选择顺序来加载
服务器路径问题
分类:
① 带协议的绝对路径:http://localhost:8080/projname/img/pic.jpg
② 不带协议的绝对路径:/projname/img/pic.jpg
③ 相对路径:
当前目录 ./ 可省略
上级目录 ../ 不可省略
① 带协议的绝对路径:http://localhost:8080/projname/img/pic.jpg
② 不带协议的绝对路径:/projname/img/pic.jpg
③ 相对路径:
当前目录 ./ 可省略
上级目录 ../ 不可省略
@WebServlet注解式配置(Servlet3.0+支持)
@WebServlet(
name = "TestWebServlet", // 设置 Servlet 的映射名字(通常与类名一致)
/*value = {"/demo", "/web"},*/
urlPatterns = {"/demo01", "/web01"}, // 设置 Servlet 访问资源名(value同urlPatterns)
loadOnStartup = 1, // 设置 Servlet 启动优先级
initParams = { // 设置 Servlet 启动参数
@WebInitParam(name = "username", value = "root"),
@WebInitParam(name = "password", value = "123456"),
}
)
name = "TestWebServlet", // 设置 Servlet 的映射名字(通常与类名一致)
/*value = {"/demo", "/web"},*/
urlPatterns = {"/demo01", "/web01"}, // 设置 Servlet 访问资源名(value同urlPatterns)
loadOnStartup = 1, // 设置 Servlet 启动优先级
initParams = { // 设置 Servlet 启动参数
@WebInitParam(name = "username", value = "root"),
@WebInitParam(name = "password", value = "123456"),
}
)
name:任意起的当前Servlet的名字
value:配置url路径,该路径在当前项目中必须唯一
urlPatterns:配置url路径,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建时机
value:配置url路径,该路径在当前项目中必须唯一
urlPatterns:配置url路径,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建时机
【快捷创建】包下 Alt+Insert >> Create New Servlet >>
输入类名即可同时创建注解和类, 只需要写 value 配置 url 路径和请求处理代码即可
输入类名即可同时创建注解和类, 只需要写 value 配置 url 路径和请求处理代码即可
页面显示控制
① 默认只有 index.jsp 时会只显示其为首页
② 如果写了 index.html 页面则会以其优先为首页
③ 默认页面找不到时显示的页面
<welcome-file-list>
<welcome-file>page.html</welcome-file>
<welcome-file>page.htm</welcome-file>
<welcome-file>page.jsp</welcome-file>
</welcome-file-list>
<welcome-file>page.html</welcome-file>
<welcome-file>page.htm</welcome-file>
<welcome-file>page.jsp</welcome-file>
</welcome-file-list>
<error-page>
<!--当页面未找到报404时显示 location 标签指定的页面-->
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<!--当页面未找到报404时显示 location 标签指定的页面-->
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
ServletConfig与ServletContext
ServletConfig 接口
是一个配置对象,通过 web.xml 或 注解方式配置 Servlet 参数后,可以通过 ServletConfig 对象获取初始化参数。
1. ServletConfig 对象是由服务器创建的,通过 Servlet 的 init 方法传递到 Servlet 中;
2. 作用:
获取 Servlet 名称使用 getServletName();
获取 Servlet 初始化参数 getInitParameter(); getInitParameterNames();
获取 ServletContext 对象
3. 获取 ServletContext 对象:继承 HttpServlet 后直接调用 Servlet 接口的 getServletContext() 方法。
2. 作用:
获取 Servlet 名称使用 getServletName();
获取 Servlet 初始化参数 getInitParameter(); getInitParameterNames();
获取 ServletContext 对象
3. 获取 ServletContext 对象:继承 HttpServlet 后直接调用 Servlet 接口的 getServletContext() 方法。
Demo
ServletContext 接口
是一个域对象(上下文对象),用来存储数据。
全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。
全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。
1. 当服务器启动时,会为服务器中的每一个web应用创建一个 ServletContext 对象;
2. 作用:
① 实现多个 Servlet 数据共享
② 获取全局初始化参数
③ 获取资源在服务器上的真实磁盘路径
④ 用 ServletContext 实现请求转发
2. 作用:
① 实现多个 Servlet 数据共享
② 获取全局初始化参数
③ 获取资源在服务器上的真实磁盘路径
④ 用 ServletContext 实现请求转发
① 数据共享
public Object getAttribute(String name) 获取域中指定参数名称的值
public void removeAttribute(String name) 将指定的参数和值移除
public void setAttribute(String name, Object object) 存储参数和值到到域中
public void removeAttribute(String name) 将指定的参数和值移除
public void setAttribute(String name, Object object) 存储参数和值到到域中
Demo
② 获取全局初始化参数
<!--全局初始化参数:整个web应用,随着服务器的启动而初始化-->
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>1234</param-value>
</context-param>
<!--或注解方式配置初始化参数-->
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>1234</param-value>
</context-param>
<!--或注解方式配置初始化参数-->
public String getInitParameter(String name) 获取初始化参数
public java.util.Enumeration<E> getInitParameterNames() 获取初始化参数集合
public java.util.Enumeration<E> getInitParameterNames() 获取初始化参数集合
Demo
③ 获取资源在服务器上的真实磁盘路径
public String getRealPath(String path) 获取资源的真实路径
根据项目的当前路径 / 拼接,注意参数给的时候也是相对于 / 当前路径。
根据项目的当前路径 / 拼接,注意参数给的时候也是相对于 / 当前路径。
Demo
案例:统计站点访问次数
Demo
Servlet集成JDBC三层架构
注意事项:
1. 路径配置,注解中的value路径、html中的路径;
2. QueryRunner注意传参时的实体类参数;
3. 确保数据库配置文件正确,能够正确被DruidUtils加载到;
1. 路径配置,注解中的value路径、html中的路径;
2. QueryRunner注意传参时的实体类参数;
3. 确保数据库配置文件正确,能够正确被DruidUtils加载到;
Servlet生命周期
生命周期
// 监听 Servlet 的初始化——通过浏览器页面请求调用Servlet时仅初始化 1 次【单例模式】
void init(ServletConfig var1) throws ServletException;
// 处理 Servlet 的数据请求和响应
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
// 监听 Servlet 进行销毁——服务器关闭的时候会销毁 Servlet
void destroy();
void init(ServletConfig var1) throws ServletException;
// 处理 Servlet 的数据请求和响应
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
// 监听 Servlet 进行销毁——服务器关闭的时候会销毁 Servlet
void destroy();
线程安全
尽可能使用局部变量。
初始化参数
xml或注解。
Servlet单示例多线程
1. Servlet 在服务器中只会创建一个实例
2. 当多个请求同时请求一个 Servlet 时,就会根据 tomcat 中的 server.xml 文件中的 <Connector> 标签配置线程池,然后当项目启动时,根据项目中 web.xml 初始化线程池
3. 当请求到达时,Servlet 容器通过调度线程池中等待状态的线程给请求
4. 线程执行 Servlet 的 service 方法
5. 请求结束,放回线程池,等待被调用
2. 当多个请求同时请求一个 Servlet 时,就会根据 tomcat 中的 server.xml 文件中的 <Connector> 标签配置线程池,然后当项目启动时,根据项目中 web.xml 初始化线程池
3. 当请求到达时,Servlet 容器通过调度线程池中等待状态的线程给请求
4. 线程执行 Servlet 的 service 方法
5. 请求结束,放回线程池,等待被调用
优点:
* Servlet 单实例,减少了产生 Servlet 的开销
* 通过线程池来响应多个请求,提高了请求的响应时间
缺点:
* 在 Servlet 中尽量避免使用成员变量,因为成员变量属于对象实例,而 Servlet 是单实例,所以相当于这个成员变量是多线程共享,存在线程不安全的问题。
* Servlet 单实例,减少了产生 Servlet 的开销
* 通过线程池来响应多个请求,提高了请求的响应时间
缺点:
* 在 Servlet 中尽量避免使用成员变量,因为成员变量属于对象实例,而 Servlet 是单实例,所以相当于这个成员变量是多线程共享,存在线程不安全的问题。
HTTP
HTTP协议
协议:两个设备进行数据交换的约定。
HTTP协议:超文本(字符/音频/视频/图片)传输协议,基于TCP协议。
HTTP协议:超文本(字符/音频/视频/图片)传输协议,基于TCP协议。
HTTP请求报文(图)
Request Method:请求方式(GET/POST)
Protocol:http协议版本
Content-Type:请求正文的数据类型
User-Agent:请求的浏览器类型
- 请求行:
Request Method:请求方式(GET/POST)
Protocol:http协议版本
- 请求头:
Content-Type:请求正文的数据类型
User-Agent:请求的浏览器类型
- 请求数据:
HTTP响应报文(图)
Refesh:定时跳转
Content-disposition:文件下载
- 响应行:
- 响应头:
Location:与302状态码组合完成重定向功能
Refesh:定时跳转
Content-disposition:文件下载
- 响应数据:
HTTP请求执行流程
互联网域名解析(DNS)
- 发起请求
- 域名解析
互联网域名解析(DNS)
- 执行请求
- 响应请求
GET/POST请求区别
● get只能传递1kb以下的数据;post可以传递大数据
● get请求参数会直接拼接到Request URL上(&);post请求参数是在请求正文中,更安全
● get主要用于获取/查询数据;post主要用于更新数据/上传文件
● get请求参数会直接拼接到Request URL上(&);post请求参数是在请求正文中,更安全
● get主要用于获取/查询数据;post主要用于更新数据/上传文件
常用响应状态码
200:服务器响应成功
302:页面重定向
304:页面无变化,无需重新请求服务器
404:没有对应的服务器资源
500:服务器内部错误
302:页面重定向
304:页面无变化,无需重新请求服务器
404:没有对应的服务器资源
500:服务器内部错误
请求&响应
response 对象
操作响应行
response.setStatus() 操作响应状态码,如200,302
response.sendError() 操作响应错误码,如404
response.sendError() 操作响应错误码,如404
操作响应头
response.setHeader() 覆盖原有响应头的值
response.addHeader() 在原有的响应头的基础上添加新值(Cookie)
response.addHeader() 在原有的响应头的基础上添加新值(Cookie)
操作响应正文
response.getWriter().println("响应正文内容") 返回可将字符文本发送到客户端的 java.io.PrintWriter 对象
操作响应中文乱码
// ● 终极方案:同时设置服务器的编码,设置浏览器解码方式
response.setContentType("text/html;charset=utf-8");
// 其他方案:分别设置服务器编码、浏览器解码
response.setCharacterEncoding("utf-8") 设置服务器的编码方式
response.setHeader("Content-Type", "text/html;charset=utf-8") 设置浏览器的解码方式
response.setContentType("text/html;charset=utf-8");
// 其他方案:分别设置服务器编码、浏览器解码
response.setCharacterEncoding("utf-8") 设置服务器的编码方式
response.setHeader("Content-Type", "text/html;charset=utf-8") 设置浏览器的解码方式
浏览器的解码方式不固定
定时跳转
/*定时跳转*/
response.setHeader("refresh", "5;url=/demo/demo02"); // 5s后跳转demo02
response.setHeader("refresh", "5;url=/demo/demo02"); // 5s后跳转demo02
重定向
// 方式一:设置 Status Code=302 和 Location=url
response.setStatus(302);
response.setHeader("location", "/projname/success.html");
// ● 方式二:本质还是 Status Code=302 和 Location=url
response.sendRedirect("/projname/success.html");
response.sendRedirect(request.getContextPath() + File.separator + "资源/页面");
response.setStatus(302);
response.setHeader("location", "/projname/success.html");
// ● 方式二:本质还是 Status Code=302 和 Location=url
response.sendRedirect("/projname/success.html");
response.sendRedirect(request.getContextPath() + File.separator + "资源/页面");
原理:
浏览器发送http请求 >> web服务器回复响应状态码302+响应头location给浏览器 >> 浏览器收到302则自动再发送1个http请求(url+location) >> 服务器根据新请求的url寻找资源响应给浏览器
浏览器发送http请求 >> web服务器回复响应状态码302+响应头location给浏览器 >> 浏览器收到302则自动再发送1个http请求(url+location) >> 服务器根据新请求的url寻找资源响应给浏览器
特点:
1. 重定向是客户端行为
2. 重定向是浏览器做了至少 2 次的访问请求
3. 重定向浏览器地址改变
4. 重定向两次跳转之间传输的信息会丢失(request生命周期为单次请求)
5. 重定向可以定向到任何web资源(当前站点/外部站点)
1. 重定向是客户端行为
2. 重定向是浏览器做了至少 2 次的访问请求
3. 重定向浏览器地址改变
4. 重定向两次跳转之间传输的信息会丢失(request生命周期为单次请求)
5. 重定向可以定向到任何web资源(当前站点/外部站点)
request 对象
操作请求行
request.getMethod() 获取请求方式
request.getRequestURI() 获取请求路径
request.getQueryString() 获取请求路径上的参数,仅限于GET
request.getRequestURI() 获取请求路径
request.getQueryString() 获取请求路径上的参数,仅限于GET
操作请求头
request.getHeader(String name) 根据请求头名称获取值,如 User-Agent
操作请求参数
request.getParameter() 获取指定参数名称的值
request.getParameterValues() 获取指定参数名称的一组值
request.getParameterMap() 返回此请求的参数的 java.util.Map
request.getParameterNames() 获取所有的参数名称
request.getParameterValues() 获取指定参数名称的一组值
request.getParameterMap() 返回此请求的参数的 java.util.Map
request.getParameterNames() 获取所有的参数名称
Demo
操作请求数据
@WebServlet(name = "任意名字", urlPatterns = "/资源路径")
<!--默认提交方式为 GET,同时可省略,POST不可省略-->
<form method="post" action="/projname/资源路径">...</form>
<form method="post" action="/projname/资源路径">...</form>
操作请求中文乱码
/* POST请求正文乱码,两种方式都可以;GET是QueryString乱码,只能用方式二 */
// ● 终极方案:设置请求正文编码,用于POST在Tomcat8.5环境。
request.setCharacterEncoding("utf-8");
// 其他方案:将请求中拿到的乱码字符串编码成iso8859-1字节,再将字节解码为utf-8字符串,通用Tomcat7.0&8.5环境。
String serverEncoding = request.getCharacterEncoding();
String tmp = request.getParameter("username");
String username = new String(tmp.getBytes(serverEncoding), "utf-8");
/* Tomcat8.5比7.0中新增了URIEncoding="utf-8",修复了GET请求QueryString乱码,POST请求还需设置请求正文编码 */
// ● 终极方案:设置请求正文编码,用于POST在Tomcat8.5环境。
request.setCharacterEncoding("utf-8");
// 其他方案:将请求中拿到的乱码字符串编码成iso8859-1字节,再将字节解码为utf-8字符串,通用Tomcat7.0&8.5环境。
String serverEncoding = request.getCharacterEncoding();
String tmp = request.getParameter("username");
String username = new String(tmp.getBytes(serverEncoding), "utf-8");
/* Tomcat8.5比7.0中新增了URIEncoding="utf-8",修复了GET请求QueryString乱码,POST请求还需设置请求正文编码 */
浏览器的编码方式固定为 utf-8
请求转发
// 转发,如提交成功自动进行一次配置路径的Servlet请求调用执行,此处为配置路径(无projname)
request.getRequestDispatcher("/资源路径").forward(request, response);
request.getRequestDispatcher("/资源路径").forward(request, response);
原理:
客户浏览器发送http请求 >> web服务器接收此请求 >> 服务器内部完成请求处理和转发动作 >> 将目标资源响应给客户
客户浏览器发送http请求 >> web服务器接收此请求 >> 服务器内部完成请求处理和转发动作 >> 将目标资源响应给客户
特点:
1. 转发是服务器行为
2. 转发是浏览器只做了 1 次访问请求
3. 转发浏览器地址不变
4. 转发两次跳转之间的信息不会丢失(request生命周期内可传递数据)
5. 转发只能将请求转发给同一个web项目内的资源
1. 转发是服务器行为
2. 转发是浏览器只做了 1 次访问请求
3. 转发浏览器地址不变
4. 转发两次跳转之间的信息不会丢失(request生命周期内可传递数据)
5. 转发只能将请求转发给同一个web项目内的资源
request域对象
request域对象生命周期:在一次请求中,请求结束服务器响应时即销毁。
request域对象共享数据方法
request.setAttribute(name, msg); // 设置数据msg取名name
request.getAttribute(name); // 获取数据与name对应
request.removeAttribute(name); // 删除数据与name对应
request.getAttributeNames(); // 获取所有的共享数据names
request.getAttribute(name); // 获取数据与name对应
request.removeAttribute(name); // 删除数据与name对应
request.getAttributeNames(); // 获取所有的共享数据names
● 重定向中不能使用 request域对象,因为1次请求响应后该对象便销毁;
● 转发中可以使用 request域对象,因为转发只有1次请求,在域对象生命周期内。
● 转发中可以使用 request域对象,因为转发只有1次请求,在域对象生命周期内。
重定向和转发的路径问题
1. 使用相对路径时,没有区别;
2. 使用绝对路径时,重定向使用/project/资源,转发使用/资源
2. 使用绝对路径时,重定向使用/project/资源,转发使用/资源
会话技术
Cookie
客户端状态管理技术,将状态信息保存在客户端。
网景公司发明,浏览器会话技术。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称name和设置值value。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个大小限制为4kb。
网景公司发明,浏览器会话技术。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称name和设置值value。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个大小限制为4kb。
工作原理
执行流程:
1.浏览器向服务器发送请求,服务器需要创建cookie,服务器会通过响应携带cookie,
在产生响应时会产生Set-Cookie响应头,从而将cookie信息传递给了浏览器;
2.当浏览器再次向服务器发送请求时,会产生cookie请求头,将之前服务器的cookie信息再次发送给了服务器,
然后服务器根据cookie信息跟踪客户端状态。
1.浏览器向服务器发送请求,服务器需要创建cookie,服务器会通过响应携带cookie,
在产生响应时会产生Set-Cookie响应头,从而将cookie信息传递给了浏览器;
2.当浏览器再次向服务器发送请求时,会产生cookie请求头,将之前服务器的cookie信息再次发送给了服务器,
然后服务器根据cookie信息跟踪客户端状态。
图示
创建添加
// 用响应创建Cookie,等价于 response.addHeader("set-cookie", "name=value");
Cookie cookie = new Cookie(String name, String value); // Cookie: name=value
cookie.setMaxAge(seconds); // 设置Cookie的生命周期
cookie.setPath("/"); // 设置Cookie的共享范围
response.addCookie(cookie); // 添加1个Cookie
Cookie cookie = new Cookie(String name, String value); // Cookie: name=value
cookie.setMaxAge(seconds); // 设置Cookie的生命周期
cookie.setPath("/"); // 设置Cookie的共享范围
response.addCookie(cookie); // 添加1个Cookie
获取修改
// 用请求获取Cookie
Cookie[] cookies = request.getCookies(); // 获取Cookies返回数组
// 需遍历
cookie.getName();
cookie.getValue();
// 修改Cookie
cookie.setValue(String);
Cookie[] cookies = request.getCookies(); // 获取Cookies返回数组
// 需遍历
cookie.getName();
cookie.getValue();
// 修改Cookie
cookie.setValue(String);
共享范围
// 设置Cookie的共享范围
cookie.setPath("/");
cookie.setPath("/");
/ 当前项目下所有资源均可共享访问该Cookie对象内容
/project/demo 当前项目下只有资源demo均可共享访问该Cookie对象内容
/project/demo 当前项目下只有资源demo均可共享访问该Cookie对象内容
生命周期
// 设置Cookie生命周期,单位s
cookie.setMaxAge(int); // 7天:7*24*60*60
cookie.setMaxAge(int); // 7天:7*24*60*60
- <0:浏览器会话结束/浏览器关闭,内存存储(默认)
- =0:失效
- >0:生效时间,单位s
编码与解码
中文:Unicode,4个字节 英文:ASCII,2个字节
Cookie的中文乱码需要进行编码和解码处理:
编码:java.net.URLEncoder 的 URLEncoder.encode(String str, String encoding)
解码:java.net.URLDecoder 的 URLDecoder.decode(String str, String encoding)
编码:java.net.URLEncoder 的 URLEncoder.encode(String str, String encoding)
解码:java.net.URLDecoder 的 URLDecoder.decode(String str, String encoding)
Demo
chrome浏览器查看cookie信息
chrome://settings/content/cookies
chrome://settings/siteData
优劣
优点:
● 可配置三种到期规则:1次请求就失效,1次浏览器会话(关闭)失效,配置永久生效
● 简单性:基于文本的轻量结构,简单键值对
● 数据持久性:虽然Cookie可被客户端浏览器的过期处理和干预,但Cookie通常也是客户端上持续时间最长的数据保留形式
● 可配置三种到期规则:1次请求就失效,1次浏览器会话(关闭)失效,配置永久生效
● 简单性:基于文本的轻量结构,简单键值对
● 数据持久性:虽然Cookie可被客户端浏览器的过期处理和干预,但Cookie通常也是客户端上持续时间最长的数据保留形式
缺点:
● 大小受到限制:大多数浏览器的Cookie只有4kb大小的限制
● 用户配置禁用:客户浏览器设置了禁用接收Cookie的能力,限制了该功能
● 潜在安全风险:用户可能会操纵篡改浏览器上的Cookie,会造成Cookie应用程序执行失败的问题
● 大小受到限制:大多数浏览器的Cookie只有4kb大小的限制
● 用户配置禁用:客户浏览器设置了禁用接收Cookie的能力,限制了该功能
● 潜在安全风险:用户可能会操纵篡改浏览器上的Cookie,会造成Cookie应用程序执行失败的问题
案例:记录用户上一次访问时间
LastVisitTimeServlet
案例:记录商品的浏览历史信息
HistoryServlet
ShowHistoryServlet
Session
三大域对象
request 1个用户可有多个;session 1个用户1个;servletContext 所有用户共用1个。
为了节省空间,提高效率,ServletContext 中要放必须的、重要的、所有用户需要共享的线程安全的一些信息。
为了节省空间,提高效率,ServletContext 中要放必须的、重要的、所有用户需要共享的线程安全的一些信息。
服务器状态管理技术,将状态信息保存在服务器端。
是sun公司定义的一个接口。
是sun公司定义的一个接口。
工作原理
执行流程:
1. 第一次请求,请求头中没有jsessionid的cookie,当访问到对应的servlet资源时,执行到getSession()会创建HttpSession对象;进而响应时就将session的id作为cookie的value,响应到浏览器 Set-cookie:jsessionid=xxxx;
2. 再一次请求时,http请求中就有一个cookie:jsessionid=xxxx信息,那么该servlet就可以通过getSession()获取到jsessionid在服务器内查找对应的session对象,有就使用,无就创建。
1. 第一次请求,请求头中没有jsessionid的cookie,当访问到对应的servlet资源时,执行到getSession()会创建HttpSession对象;进而响应时就将session的id作为cookie的value,响应到浏览器 Set-cookie:jsessionid=xxxx;
2. 再一次请求时,http请求中就有一个cookie:jsessionid=xxxx信息,那么该servlet就可以通过getSession()获取到jsessionid在服务器内查找对应的session对象,有就使用,无就创建。
图示
基本使用
// 获取session对象
HttpSession session = request.getSession();
// 获取session对象的唯一标识:sessionID (JSESSIONID=E925DE1EF00F7944537C01A3BC0E2688)
String jsessionid = session.getId();
// 销毁session对象中的jsessionid
session.invalidate();
HttpSession session = request.getSession();
// 获取session对象的唯一标识:sessionID (JSESSIONID=E925DE1EF00F7944537C01A3BC0E2688)
String jsessionid = session.getId();
// 销毁session对象中的jsessionid
session.invalidate();
数据共享
// 往 session 中存储 msg
HttpSession session = request.getSession();
session.setAttribute("msg", "helloSession");
// 获取 msg
HttpSession session = request.getSession();
Object msg = session.getAttribute("msg");
// 删除域对象中的数据
session.removeAttribute("msg");
HttpSession session = request.getSession();
session.setAttribute("msg", "helloSession");
// 获取 msg
HttpSession session = request.getSession();
Object msg = session.getAttribute("msg");
// 删除域对象中的数据
session.removeAttribute("msg");
生命周期
一般都是默认值 30 分钟,无需更改。
web.xml
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<session-timeout>30</session-timeout>
</session-config>
浏览器关闭:销毁Cookie中的jsessionid=xxx,原session对象会保留默认30min后才销毁,30分钟后为新的session;
session销毁:调用 session.invalidate() 方法后,立即将session对象销毁,再次访问时会创建新的session。
session销毁:调用 session.invalidate() 方法后,立即将session对象销毁,再次访问时会创建新的session。
案例:使用验证码登陆和共享用户信息
c3p0连接池
c3p0-0.9.5.4.jar
commons-dbutils-1.7.jar
mchange-commons-java-0.2.16.jar
mysql-connector-java-5.1.48.jar
commons-dbutils-1.7.jar
mchange-commons-java-0.2.16.jar
mysql-connector-java-5.1.48.jar
DBUtils
DAOImpl
页面和Servlet
login.html
CreateCodeServlet
LoginServlet
ShowServlet
http请求中4大共享数据方式
ServletContext
生命周期为服务器开启和关闭,而且所有用户都会共享,范围过大,保密性不高。
request
生命周期太短,一次请求就丢失,无法再重定向后再次获取内容
cookie
存储在客户端浏览器,不安全!客户端浏览器可对cookie进行查看或修改,而且cookie无法定义特殊符号
session
存储在服务器,默认30分钟才销毁更新,或者服务器中主动销毁,适合用户登陆信息的共享
Cookie工具类
CookieUtils
过滤器
基本信息
对客户端向服务器发送的请求进行过滤,用于在请求之前处理资源的组件。
Filter和Listener都属于Servlet中的高级部分,Filter是最为实用的技术。
Filter和Listener都属于Servlet中的高级部分,Filter是最为实用的技术。
过滤器链
请求时,从客户端到服务端顺序处理;
响应时,从服务端到客户端顺序处理。
> 遵从原则:先过滤,后放行。
响应时,从服务端到客户端顺序处理。
> 遵从原则:先过滤,后放行。
工作原理
执行流程:
1. 浏览器发起请求
2. 服务器会根据这个请求,创建 request 对象及 response 对象
3. 过滤器会持有 request 对象及 response 对象
4. 只有当过滤器放行之后,request 对象及 response 对象才会传给 Servlet
1. 浏览器发起请求
2. 服务器会根据这个请求,创建 request 对象及 response 对象
3. 过滤器会持有 request 对象及 response 对象
4. 只有当过滤器放行之后,request 对象及 response 对象才会传给 Servlet
图示
生命周期
* 随着服务器的初始化而初始化
* 随着服务器的关闭而销毁
* 随着服务器的关闭而销毁
基本使用
开发步骤:
1. 自定义类实现 Filter 接口(包:javax.servlet.Filter)
2. 重写 init() doFilter() destroy() 三个方法
3. 在 web.xml 中配置过滤器:①声明过滤器 ②配置过滤器的过滤路径
1. 自定义类实现 Filter 接口(包:javax.servlet.Filter)
2. 重写 init() doFilter() destroy() 三个方法
3. 在 web.xml 中配置过滤器:①声明过滤器 ②配置过滤器的过滤路径
FilterDemo
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter01 过滤器的初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter01 放行之前");
// 通过过滤器链操作:放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter01 放行之后");
}
@Override
public void destroy() {
System.out.println("Filter01 过滤器的销毁");
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter01 过滤器的初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter01 放行之前");
// 通过过滤器链操作:放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter01 放行之后");
}
@Override
public void destroy() {
System.out.println("Filter01 过滤器的销毁");
}
}
web.xml
<!--声明Filter01过滤器-->
<filter>
<filter-name>Filter01</filter-name>
<filter-class>com.demo.filter.Filter01</filter-class>
</filter>
<!--配置Filter01的过滤路径-->
<filter-mapping>
<filter-name>Filter01</filter-name>
<!--/ 代表所有资源都过滤-->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Filter01</filter-name>
<filter-class>com.demo.filter.Filter01</filter-class>
</filter>
<!--配置Filter01的过滤路径-->
<filter-mapping>
<filter-name>Filter01</filter-name>
<!--/ 代表所有资源都过滤-->
<url-pattern>/*</url-pattern>
</filter-mapping>
配置方式
web.xml
<!--无限接近SpringMVC中文乱码解决方案-->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.demo.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.demo.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
步骤:声明过滤器,配置过滤路径。
匹配规则
<url-pattern>标签中的匹配规则:
* / 完全匹配
* /开头,*结尾 目录匹配
* *开头,后缀名结尾 后缀名匹配
* / 完全匹配
* /开头,*结尾 目录匹配
* *开头,后缀名结尾 后缀名匹配
注解配置
@WebFilter注解
WebInitParam[] initParams() default {}; //配置初始化参数
String filterName() default ""; //配置过滤器名称
String[] servletNames() default {}; //配置过滤的Servlet
String[] urlPatterns() default {}; //配置过滤路径
WebInitParam[] initParams() default {}; //配置初始化参数
String filterName() default ""; //配置过滤器名称
String[] servletNames() default {}; //配置过滤的Servlet
String[] urlPatterns() default {}; //配置过滤路径
使用注解
Demo
中文乱码
方式一:过滤器处理
页面乱码处理 login.jsp 不会乱码
html 请求和响应乱码
web.xml
Demo
方式二:继承(通用Servlet)
案例:实现自动登陆
逻辑流程
1. 登陆账户后,根据是否勾选了自动登录选项框
2. 判断是否访问和登陆相关资源
* 如果是,直接放行
* 如果不是,判断是否已经在登陆状态
* 如果已登陆,直接放行
* 如果不是,需要从cookie中取出存储的用户信息,进行登陆操作
* 如果登陆成功,直接放行
* 如果登陆失败,就跳转到登陆页面
2. 判断是否访问和登陆相关资源
* 如果是,直接放行
* 如果不是,判断是否已经在登陆状态
* 如果已登陆,直接放行
* 如果不是,需要从cookie中取出存储的用户信息,进行登陆操作
* 如果登陆成功,直接放行
* 如果登陆失败,就跳转到登陆页面
流程图示
代码逻辑
web.xml
login.jsp
AutoLoginServlet
AutoLoginFilter
ShowIndexServlet
案例:请求中的敏感词过滤
核心逻辑
使用动态代理模式在过滤器中增强 request.getParameter() 方法
使其在浏览器发起请求时拥有过滤敏感词功能。
使其在浏览器发起请求时拥有过滤敏感词功能。
SensitiveWordsFilter
监听器
基本信息
概念:监听器就是一个实现了特定接口的Java类
分类
一类监听器:监听域对象的创建、销毁
二类监听器:监听域对象中的属性变更(属性设置、属性替换、属性移除)
三类监听器:监听域对象中的java对象的绑定
Servlet监听器
事件源:request、session、servletContext三大域对象
监听器:Servlet对象(三种监听器)
绑定:web.xml配置 或 @WebListener注解
事件:域对象发生改变
工作原理
1. 实现了特定接口的类为监听器,用来监听另一个Java类的方法调用或者属性改变;
2. 当被监听的对象发生了方法调用或者属性改变后,监听器的对应方法就会立即执行。
2. 当被监听的对象发生了方法调用或者属性改变后,监听器的对应方法就会立即执行。
基本使用
一类
ServletContextListener
监听ServletContext域对象的创建、销毁
// 服务器启动,ServletContext域对象创建,该监听器方法则执行
public void contextInitialized(ServletContextEvent servletContextEvent)
// 服务器关闭,ServletContext域对象销毁,该监听器方法则执行
public void contextDestroyed(ServletContextEvent servletContextEvent)
public void contextInitialized(ServletContextEvent servletContextEvent)
// 服务器关闭,ServletContext域对象销毁,该监听器方法则执行
public void contextDestroyed(ServletContextEvent servletContextEvent)
HttpSessionListener
监听HttpSession域对象的创建、销毁
// 服务器第一次调用getSession方法时,该监听器方法被执行
public void sessionCreated(HttpSessionEvent httpSessionEvent)
// session过期/调用了invalidate方法销毁session时,该监听器方法被执行
public void sessionDestroyed(HttpSessionEvent httpSessionEvent)
public void sessionCreated(HttpSessionEvent httpSessionEvent)
// session过期/调用了invalidate方法销毁session时,该监听器方法被执行
public void sessionDestroyed(HttpSessionEvent httpSessionEvent)
问题:
* 访问一个Servlet会不会创建session对象?会!
* 访问一个JSP页面会不会创建session对象?会!
* 访问一个HTML页面会不会创建session对象?不会!
* 访问一个Servlet会不会创建session对象?会!
* 访问一个JSP页面会不会创建session对象?会!
* 访问一个HTML页面会不会创建session对象?不会!
ServletRequestListener
监听ServletRequest域对象的创建、销毁
// 客户端向服务器发送了一个请求,服务器就会为该请求创建一个request对象,该监听器方法就被执行
public void requestInitialized(ServletRequestEvent servletRequestEvent)
// 当服务器为这次请求做出了响应后,将request对象销毁,该监听器方法就被执行
public void requestDestroyed(ServletRequestEvent servletRequestEvent)
public void requestInitialized(ServletRequestEvent servletRequestEvent)
// 当服务器为这次请求做出了响应后,将request对象销毁,该监听器方法就被执行
public void requestDestroyed(ServletRequestEvent servletRequestEvent)
问题:
* 访问一个Servlet会不会创建request对象?会!
* 访问一个JSP页面会不会创建request对象?会!
* 访问一个HTML页面会不会创建request对象?不会!
* 访问一个Servlet会不会创建request对象?会!
* 访问一个JSP页面会不会创建request对象?会!
* 访问一个HTML页面会不会创建request对象?不会!
二类
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
三类
HttpSessionBindingListener
监听session域对象中的java对象的状态(绑定和解绑)
- 绑定:将java对象存储到session域对象
- 解绑:将java对象从session域对象移除
开发步骤:Java对象实现该接口,重写方法。
Demo
开发步骤
定义类实现监听器接口
重写方法
配置
配置 web.xml
<listener>
<listener-class>Listener的全限定名</listener-class>
</listener>
<listener-class>Listener的全限定名</listener-class>
</listener>
@注解
@WebListener
Demo
案例:统计在线人数
逻辑图示
代码实现
login.html
User
LoginServlet
LogoutServlet
ShowIndexServlet
综合案例:用户管理
登陆
登陆成功,修改登陆状态,跳转首页
登陆失败,跳转到登陆页面
登陆失败,跳转到登陆页面
首页
不再登陆状态,提示用户登陆
在登陆状态,显示用户名
显示注销登陆按钮
显示用户列表
在登陆状态,显示用户名
显示注销登陆按钮
显示用户列表
注销
session.removeAttribute / session.invalidate
注销成功,跳转到登陆页面
注销失败,跳转到首页,重新手动注销登陆
注销成功,跳转到登陆页面
注销失败,跳转到首页,重新手动注销登陆
用户列表
不在登陆状态,不显示用户列表
在登陆状态:
· 操作数据库,获取所有用户
· 通过table标签将用户列表显示出来
在登陆状态:
· 操作数据库,获取所有用户
· 通过table标签将用户列表显示出来
删除用户
在table的每一行中都添加一个删除按钮
在添加删除按钮时,会给出所在行的记录的id
在点击删除按钮时,请求删除用户的DeleteUserServlet
删除成功与否都跳转首页
在添加删除按钮时,会给出所在行的记录的id
在点击删除按钮时,请求删除用户的DeleteUserServlet
删除成功与否都跳转首页
批量删除
在table的每一行中都添加一个复选框
在每个删除标签中,需要给给每个复选框,设定name属性、value属性
· name="ids"
· value就是每一行记录的id
当点击批量删除按钮时,请求批量删除的Servlet
DeleteUsersServlet删除成功与否都跳转到首页
在每个删除标签中,需要给给每个复选框,设定name属性、value属性
· name="ids"
· value就是每一行记录的id
当点击批量删除按钮时,请求批量删除的Servlet
DeleteUsersServlet删除成功与否都跳转到首页
添加用户
首页新加一个添加用户按钮
点击添加用户按钮之后,跳转到添加用户页面
当点击提交按钮,开始添加用户
AddUserServlet 添加成功跳转首页,添加失败,跳转到添加用户页面
点击添加用户按钮之后,跳转到添加用户页面
当点击提交按钮,开始添加用户
AddUserServlet 添加成功跳转首页,添加失败,跳转到添加用户页面
修改用户
在table的每一行中都添加一个修改按钮
点击修改用户按钮之后,跳转到修改用户页面ShowUpdateUserServlet:
· 获取要修改的用户信息
· 生成要修改用户的页面
点击提交按钮,开始修改用户UpdateUserServlet
· 修改成功跳转到首页
· 修改失败,跳转到修改用户页面
点击修改用户按钮之后,跳转到修改用户页面ShowUpdateUserServlet:
· 获取要修改的用户信息
· 生成要修改用户的页面
点击提交按钮,开始修改用户UpdateUserServlet
· 修改成功跳转到首页
· 修改失败,跳转到修改用户页面
通用Servlet
BaseServlet
充当了父类的通用Servlet,所有自定义的Servlet都继承于BaseServlet
实现请求的分发,不同的请求交给不同的方法进行处理
充当了父类的通用Servlet,所有自定义的Servlet都继承于BaseServlet
实现请求的分发,不同的请求交给不同的方法进行处理
高级版
login.html
BaseServlet
UserServlet
生命周期划分
pageContext
作用在当前页面
request
作用在一次请求中
cookie
默认随浏览器关闭而销毁(存储在浏览器,可设置更长生命周期)
session
作用在一次会话中,随浏览器关闭而销毁
filter
随服务器初始化而初始化,服务器关闭而关闭
listener
随服务器初始化而初始化,服务器关闭而关闭
ServletContext / application
作用在服务器开启和关闭
JSP
JSP原理
概念
JSP,java server page,和Servlet一样,是sun公司定义的一种动态网页技术。本质就是一个servlet,可以使用jsp代替servlet来处理请求,显示数据。
即 jsp可以理解为在html页面中写java代码,或 一个可以获取java数据的html文件。
即 jsp可以理解为在html页面中写java代码,或 一个可以获取java数据的html文件。
JSP为什么本质是一个Servlet?
testjsp.jsp 继承自 testjsp.java/testjsp.class 继承自 HttpJspPage 继承自 JspPage 继承自 Servlet。
Tomcat镜像中将jsp文件转义为了java文件和编译后的class字节码文件:
C:\Users\Administrator\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_53_demo61\work\Catalina\localhost\demo\org\apache\jsp\demo.java
testjsp.jsp 继承自 testjsp.java/testjsp.class 继承自 HttpJspPage 继承自 JspPage 继承自 Servlet。
Tomcat镜像中将jsp文件转义为了java文件和编译后的class字节码文件:
C:\Users\Administrator\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_53_demo61\work\Catalina\localhost\demo\org\apache\jsp\demo.java
查看生成java文件
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.5.53
* Generated at: 2020-04-26 07:19:38 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.5.53
* Generated at: 2020-04-26 07:19:38 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
/ *
* 由Apache Tomcat的Jasper组件生成
* 版本:Apache Tomcat/8.5.53
* 生成时间:2020-xx-xx xx:xx:xx
* 注意:此文件的最后修改时间设置为生成后源文件的最后修改时间,以帮助跟踪修改。
* /
* 由Apache Tomcat的Jasper组件生成
* 版本:Apache Tomcat/8.5.53
* 生成时间:2020-xx-xx xx:xx:xx
* 注意:此文件的最后修改时间设置为生成后源文件的最后修改时间,以帮助跟踪修改。
* /
① 当在浏览器上输入 http://localhost:8080/demo/index.jsp
② 服务器tomcat得到请示,会通过JspServlet将后缀名是.jsp的请求处理
③ 会将index.jsp翻译成index_jsp.java文件
④ 再将index_jsp.java文件编译成index_jsp.class文件
⑤ jvm将.class加载运行
⑥ 服务器生成响应,响应信息中就包含了jsp页面上的html代码
② 服务器tomcat得到请示,会通过JspServlet将后缀名是.jsp的请求处理
③ 会将index.jsp翻译成index_jsp.java文件
④ 再将index_jsp.java文件编译成index_jsp.class文件
⑤ jvm将.class加载运行
⑥ 服务器生成响应,响应信息中就包含了jsp页面上的html代码
JSP脚本
脚本
可以在页面上写java代码
分类:
● 声明脚本:<%! Java代码 %>
在jsp对应的java类中生成一个成员变量
● 片段脚本:<% Java代码 %>
在jsp对应的java类的_jspService方法中,生成一个局部变量
● 输出脚本:<%= Java代码 %>
向浏览器输出内容,相当于 response.getWriter().write(Java代码)
在jsp对应的java类的 out.prinln() 中
● 声明脚本:<%! Java代码 %>
在jsp对应的java类中生成一个成员变量
● 片段脚本:<% Java代码 %>
在jsp对应的java类的_jspService方法中,生成一个局部变量
● 输出脚本:<%= Java代码 %>
向浏览器输出内容,相当于 response.getWriter().write(Java代码)
在jsp对应的java类的 out.prinln() 中
注释
jsp文件中可以有 jsp + html + java 代码
即 可以使用上述三种语言的注释标签。
即 可以使用上述三种语言的注释标签。
● jsp:<%-- 注释 --%>
jsp注释不会生成到jsp对应的java文件中
● html:<!-- 注释 -->
● java:/* 注释1 */ // 注释2
html、java注释均会生成到jsp对应的java文件中
jsp注释不会生成到jsp对应的java文件中
● html:<!-- 注释 -->
● java:/* 注释1 */ // 注释2
html、java注释均会生成到jsp对应的java文件中
JSP指令
用于指示jsp执行某些操作或特性行为/效果
语法
<%@ 指令名称 属性1="值1" 属性2="值2" %>
分类
page 指令
设置jsp页面的基本属性
<%@ page contentType="text/html;charset=UTF‐8" language="java" import="java.util.List" isELIgnored="false" session="false"%>
- contentType="..." 相当于 response.setContentType("...") 设置编解码方式
- language="java" jsp脚本上可以使用的语言,一般不用,默认java
- import="java.util.List" 页面上导入java包,多个包使用逗号分隔(IDEA可以导入包,默认导入jsp页面顶部-为单独的page指令导包)
- isELgnored="false" 是否忽略el表达式,默认false是不忽略
- errorPage="error.jsp" 用于指定错误页面,当前页面发生错误后,会跳转到指定的错误页面
- isErrorPage="true" 为true时可以在当前页面直接使用jsp内置对象exception,即 <%= exception.toString() %> 或 ${exception} 页面输出错误信息
- extends="org.apache.jasper.runtime.HttpJspBase" 默认继承自HttpJspBase类,不动!
taglib 指令
在当前jsp页面导入 jstl 标签库(JSP标准标签库是由JCP所制定的标准规范)
uri属性确定标签库的位置,prefix属性指定标签库的前缀
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
include 指令
嵌套其他jsp文件的jsp代码(其他jsp代码可以只是所需部分)
第一种 include指令:`通过file属性来指定被包含的页面`,当JSP转换成Servlet时引入指定文件,`一般不需要写头`
<%@ pagecontentType="text/html;charset=GB2312" language="java"errorPage=""%>
<%@ include file="head.jsp"%>
<%@ include file="body.jsp"%>
<%@ include file="tail.jsp"%>
<%@ pagecontentType="text/html;charset=GB2312" language="java"errorPage=""%>
<%@ include file="head.jsp"%>
<%@ include file="body.jsp"%>
<%@ include file="tail.jsp"%>
第二种 <jsp:include>动作元素:`通过page属性来指定被包含的页面`,当JSP页面被请求时引入指定文件,`需要写头`
可以用<jsp:param>来向所包含页传递参数。
<%@ page contentType="text/html; charset=GB2312"language="java" errorPage=""%>
<jsp:include page="head.jsp"/>
<jsp:param name="uid"value="username"/>
<jsp:param name="pwd"value="password"/>
</jsp:include>
<jsp:include page="body.jsp"/>
<jsp:include page="tail.jsp"/>
可以用<jsp:param>来向所包含页传递参数。
<%@ page contentType="text/html; charset=GB2312"language="java" errorPage=""%>
<jsp:include page="head.jsp"/>
<jsp:param name="uid"value="username"/>
<jsp:param name="pwd"value="password"/>
</jsp:include>
<jsp:include page="body.jsp"/>
<jsp:include page="tail.jsp"/>
内置对象
概念
能够在jsp页面上直接使用这些对象,一共有9个。
9大对象就是jsp页面翻译成java文件中创建的对象,所以可以可以在jsp页面中直接使用。
9大对象就是jsp页面翻译成java文件中创建的对象,所以可以可以在jsp页面中直接使用。
9大内置对象
- page:页面对象,java.lang.Object类型的page对象
- request:HttpServletRequest,javax.servlet.http.HttpServletRequest类型的request对象
- response:HttpServletResponse,javax.servlet.http.HttpServletResponse类型的response对象
- session:HttpSession,javax.servlet.http.HttpSession类型的session对象
- application:ServletContext,javax.servlet.ServletContext类型的application对象
- out:JspWriter,javax.servlet.jsp.JspWriter类型的out对象
- config:ServletConfig,javax.servlet.ServletConfig类型的config对象
- exception:Throwable,java.lang.Throwable类型的exception对象
- pageContext:pageContext,javax.servlet.jsp.PageContext类型的pageContext对象
4大域对象
pageContext
代表 page 域,但是 jsp 中 page 它的类型是 Object,所以操作 page 域我们使用的是 pageContext 对象,page 域就是指当前页面
作用在当前页面
request
作用在一次请求
对应 Servlet 域对象:HttpServletRequest
session
作用在一次会话
对应 Servlet 域对象:HttpSession
application
作用在整个项目
对应 Servlet 域对象:ServletContext
pageContext 域对象
① 获取其他内置对象
② 操作 page 域及其他域
案例:JSP实现用户登陆
login.jsp
UserServlet
BaseServlet
EL表达式
概念
el, expression language 是由 jsp 内置 jsp-api.jar 提供。
el 表达式用来替换 jsp 脚本。
el 表达式用来替换 jsp 脚本。
格式
${表达式}
代替 <%=变量值%> jsp脚本。
操作
el 运算操作
算术、关系、逻辑、三目运算 Demo
字符串判断/判空
${str == 'hello'}
${str != 'hello'}
${str != 'hello'}
${not empty str}
${empty str}
${empty str}
域对象操作 × 4
获取方式
page域: ${pageScope.name1}
request域: ${requestScope.name2}
session域: ${sessionScope.name3}
application域: ${applicationScope.name4}
简写:${name}
注意事项:
* 如果 el 表达式没有获取到结果,返回的不是 null 而是 "" 空字符串;
* ${name} 不指定域的写法,jsp 页面就会从小到大的域数据进行查找:
pageScope -> requestScope -> sessionScope -> applicationScope
* 域中的共享数据一定要区别 name 的名字,以区别不同的域;
* 如果 el 表达式没有获取到结果,返回的不是 null 而是 "" 空字符串;
* ${name} 不指定域的写法,jsp 页面就会从小到大的域数据进行查找:
pageScope -> requestScope -> sessionScope -> applicationScope
* 域中的共享数据一定要区别 name 的名字,以区别不同的域;
获取内容
数组 Demo
list Demo
map Demo
对象 Demo
web 对象操作 × 11
包含 4 个域对象:pageScope / requestScope / sessionScope / applicationScope
包含 7 个 web 对象:param / paramValues / initParam / header / headerValues / cookie / pageContext
常用:4个域对象 + cookie + pageContext
包含 7 个 web 对象:param / paramValues / initParam / header / headerValues / cookie / pageContext
常用:4个域对象 + cookie + pageContext
param <==> request.getParameter()
paramValues <==> request.getParameters()
initParam <==> 获取初始化参数
header <==> 获取单个请求头
headerValues <==> 获取一组请求头
cookie <==> 获取 Map 类型的 cookie 对象
pageContext <==> 获取 jsp 内置的 9 大对象
paramValues <==> request.getParameters()
initParam <==> 获取初始化参数
header <==> 获取单个请求头
headerValues <==> 获取一组请求头
cookie <==> 获取 Map 类型的 cookie 对象
pageContext <==> 获取 jsp 内置的 9 大对象
Demo
案例:3行实现访问量统计
<%
Integer count = (Integer) application.getAttribute("count");
count = (count == null || count == 0) ? 1 : count+1;
application.setAttribute("count", count);
%>
页面访问量:${count}次
Integer count = (Integer) application.getAttribute("count");
count = (count == null || count == 0) ? 1 : count+1;
application.setAttribute("count", count);
%>
页面访问量:${count}次
jstl标签库
概念
jstl, java standard tag library 和 el 表达式结合使用,可以让功能更加强大。
环境配置
WEB_INF/lib/ 导入jar包
jstl.jar
standard.jar
当前 jsp 页面导入标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
核心标签
set
向域中设置数据,等价于 域对象.setAttribute()
<%-- set标签:往域中设置数据 --%>
<c:set var="msg" scope="request" value="hello,jstl-set"/>
<%-- 获取 --%>
${msg}
<c:set var="msg" scope="request" value="hello,jstl-set"/>
<%-- 获取 --%>
${msg}
remove
将数据从域中移除,等价于 域对象.removeAttribute()
<%-- remove标签:从域中移除数据 --%>
<c:remove var="msg" scope="request"/>
<%-- 获取为空 --%>
${msg}
<c:remove var="msg" scope="request"/>
<%-- 获取为空 --%>
${msg}
catch
捕获异常,等价于 try-catch
<%-- catch标签:捕获异常 --%>
<c:catch var="e">
<%
int num = 1/0;
%>
</c:catch>
<%-- 获取异常信息 --%>
${e} <br>
${e.message}
<c:catch var="e">
<%
int num = 1/0;
%>
</c:catch>
<%-- 获取异常信息 --%>
${e} <br>
${e.message}
if
条件判断
<%-- if标签:条件判断 --%>
<c:set var="msg" scope="request" value="100"/>
<c:if test="${msg == 100}">
msg 等于 100
</c:if>
<c:if test="${msg != 100}">
msg 不等于 100
</c:if>
<c:set var="msg" scope="request" value="100"/>
<c:if test="${msg == 100}">
msg 等于 100
</c:if>
<c:if test="${msg != 100}">
msg 不等于 100
</c:if>
foreach
遍历数组或集合
<%
List<String> strs = new ArrayList<>();
strs.add("hello");
strs.add("world");
strs.add("OMG");
request.setAttribute("strs", strs);
%>
${strs.size()}
<%-- forEach标签:等价于普通 for 循环 --%>
<c:forEach var="i" begin="0" end="${strs.size()}" step="1">
${strs[i]}
</c:forEach>
<%-- forEach标签:等价于增强 for 循环 --%>
<c:forEach var="str" items="${strs}" varStatus="status">
${str} <br>
当前元素:${status.current} 下标:${status.index} 是否第1个元素:${status.first} 是否最尾元素:${status.last} <br>
</c:forEach>
<br>
${strs[1]}
List<String> strs = new ArrayList<>();
strs.add("hello");
strs.add("world");
strs.add("OMG");
request.setAttribute("strs", strs);
%>
${strs.size()}
<%-- forEach标签:等价于普通 for 循环 --%>
<c:forEach var="i" begin="0" end="${strs.size()}" step="1">
${strs[i]}
</c:forEach>
<%-- forEach标签:等价于增强 for 循环 --%>
<c:forEach var="str" items="${strs}" varStatus="status">
${str} <br>
当前元素:${status.current} 下标:${status.index} 是否第1个元素:${status.first} 是否最尾元素:${status.last} <br>
</c:forEach>
<br>
${strs[1]}
fotTokens
分割字符串
<%-- forTokens标签:分割字符串 --%>
<%
String s = "hello:word:OMG";
request.setAttribute("s", s);
%>
<c:forTokens items="${s}" delims=":" var="subStr" varStatus="status">
${subStr}
</c:forTokens>
<%
String s = "hello:word:OMG";
request.setAttribute("s", s);
%>
<c:forTokens items="${s}" delims=":" var="subStr" varStatus="status">
${subStr}
</c:forTokens>
格式化标签
随用随查
SQL 标签
随用随查
XML 标签
随用随查
JSTL 函数
随用随查
综合案例:显示商品列表信息
productList.jsp
bean.Product
dao.ProductDaoImpl
servlet.ProductServlet
开发模式
JSP 模式
① jsp+javaBean
jsp:请求处理、业务处理、数据库操作、数据显示
javaBean:数据封装
javaBean:数据封装
优点:开发简单
缺点:维护难,代码几乎都在 jsp 中
缺点:维护难,代码几乎都在 jsp 中
② jsp+javaBean+Servlet
jsp: 数据显示
Servlet: 请求处理、业务处理、数据库操作
javaBean: 数据封装
Servlet: 请求处理、业务处理、数据库操作
javaBean: 数据封装
优点:维护方便,开发各司其职利于模块分工,适合开发复杂项目,组件可以重用
缺点:开发难度大,对开发要求高
缺点:开发难度大,对开发要求高
BeanUtils 框架
导入3个 jar 包
commons-beanutils-1.9.4.jar
commons-collections-3.2.2.jar
commons-logging-1.2.jar
commons-collections-3.2.2.jar
commons-logging-1.2.jar
jar 包下载:
http://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi
http://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi
要求:页面上的参数 name 名需要与Bean实体类的属性名完全一致。
regist.jsp
<form action="/demo/reg" method="post">
账号:<input type="text" name="username"> <br>
密码:<input type="text" name="password"> <br>
年龄:<input type="text" name="age"> <br>
<button type="submit">注册</button>
</form>
账号:<input type="text" name="username"> <br>
密码:<input type="text" name="password"> <br>
年龄:<input type="text" name="age"> <br>
<button type="submit">注册</button>
</form>
RegServlet.doPost()
protected void doPost(... request, ... response) {
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map);
// 获取到封装了设置好jsp提交的参数的实例对象
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map);
// 获取到封装了设置好jsp提交的参数的实例对象
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
User
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
...
}
private Integer id;
private String username;
private String password;
private Integer age;
...
}
自定义 MyBeanUtils.populate()
精简版的 BeanUtils 源码实现逻辑
MVC 设计模式
Model View Controller,经典设计模式,用一种业务逻辑,数据,界面分离的方式来组织代码,
将业务聚集到一个部件中,方便程序的重复使用,提高开发效率。
将业务聚集到一个部件中,方便程序的重复使用,提高开发效率。
MVC 组成
Model
模型层,数据封装
View
视图层,数据显示
三层架构
Controller
控制层,请求处理
Service
业务层,业务逻辑
Dao
持久层,数据库操作
综合案例:JSP优化用户管理
环境
Tomcat 8.5
Intellij IDEA 2020.3
JDK 1.8
Intellij IDEA 2020.3
JDK 1.8
依赖
BeanUtils
DbUtils
C3p0
MySQL
JSTL
DbUtils
C3p0
MySQL
JSTL
配置文件
c3p0.properties
https://simple.blog.csdn.net/article/details/105849671
分页查询
主要解决页面数据加载过多,导致页面访问速度变慢的问题
分类
逻辑分页
一次性全部查询出来,存放到List中,在List中截取subList作为页数据
优:减少操作数据库的次数
缺:数据量非常大,查询时间比较长
缺:数据量非常大,查询时间比较长
物理分页
页面查询一页,就从数据库里查询一页数量的数据
优:减少单次查询数据库的时间
缺:增加了操作数据库的次数
缺:增加了操作数据库的次数
效果
第1/10页 总记录数:100 每页10条 [首页] [上一页] [下一页] [尾页]
请求和响应
请求
当前页数 currentPage
响应
当前页数 currentPage
总页数 totalPage
总记录数 totalSize
每页记录数 pageSize
当前页数据 pageList
new ScalarHandler<>( )
恶补
源码案例
https://simple.blog.csdn.net/article/details/105868086
上传下载
上传 Upload
本质就是将一台电脑中的文件根据网络协议通过 io 流传递到另一台电脑(服务器)上。
三要素
表单数据提交方式 POST
表单中设置文件上传项 <input type="file">
enctype=multipart/form-data
实现步骤
导入 jar 包
commons-fileupload-1.4.jar
commons-io-2.6.jar
前台:文件上传项(JSP)
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
描述:<input type="text" name="desc"> <br>
上传附件:<input type="file" name="file"> <br>
<button type="submit">提交</button>
</form>
描述:<input type="text" name="desc"> <br>
上传附件:<input type="file" name="file"> <br>
<button type="submit">提交</button>
</form>
后台:编写 Servlet
1. 创建磁盘文件项工厂对象 DiskFileItemFactory
2. 创建核心解析类 ServletFileUpload
3. 解析请求,获取到所有的文件项
2. 创建核心解析类 ServletFileUpload
3. 解析请求,获取到所有的文件项
文件上传API
ServletFileUpload 核心解析类
parseRequest(HttpServletRequest request) 解析请求,并获取相关文件项
setHeaderEncoding(String encoding) 解决中文文件名乱码
FileItem 文件项
boolean isFormField() 返回为true,普通字段。返回为false,就是文件
String getFieldName() 获取表单 name 字段
String getString(String encoding) 根据指定编码格式获取字段值,解决描述文本中文乱码
String getName() 获取上传文件名称
InputStream getInputStream() 获取上传文件对应的输入流
乱码和重复问题
文件名中文乱码
// 1. 创建磁盘文件项工厂对象
// 2. 创建核心解析对象
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
// 解决文件名中文乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
// 2. 创建核心解析对象
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
// 解决文件名中文乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
描述内中文乱码
// 判断 fileItem 是否是上传的文件
if (fileItem.isFormField()) {
// true:其他的 form 项
// 描述 text 的中文内容乱码问题
System.out.println(fileItem.getString("utf-8"));
} else { ... }
if (fileItem.isFormField()) {
// true:其他的 form 项
// 描述 text 的中文内容乱码问题
System.out.println(fileItem.getString("utf-8"));
} else { ... }
文件名重复问题
// 文件名 = 当前时间毫秒值 + 用户名(不重复) + 文件名
String path = serverPath + File.separator + System.currentTimeMillis() + "-" + username + "-" + fileItem.getName();
String path = serverPath + File.separator + System.currentTimeMillis() + "-" + username + "-" + fileItem.getName();
文件上传+数据库
bean
dao
service
controller
UploadServlet
FileListServlet
下载 Download
本质就是将一台电脑(服务器)中的文件根据网络协议通过 io 流传递到另外一台电脑上。
两种形式
超链接
浏览器支持的文件格式,可在浏览器打开;浏览器不支持才会提示下载
手动编写代码的方式下载
实现步骤
下载入口
<a href="${pageContext.request.contextPath}/download?fileName=${file.fileName}">下载</a>
设置媒体类型
// 1. 设置媒体类型 <- 获取下载文件的媒体类型
String fileName = request.getParameter("fileName");
String mimeType = request.getServletContext().getMimeType(fileName);
response.setContentType(mimeType);
String fileName = request.getParameter("fileName");
String mimeType = request.getServletContext().getMimeType(fileName);
response.setContentType(mimeType);
设置下载窗口
String userAgent = request.getHeader("User-Agent");
String newFileName = userAgent.contains("Chrome") ? URLEncoder.encode(fileName, "utf-8") : base64EncodeFileName(fileName);
// 2. 设置下载窗口 -> Content-Disposition
response.setHeader("Content-Disposition", "attachment;filename=" + newFileName);
String newFileName = userAgent.contains("Chrome") ? URLEncoder.encode(fileName, "utf-8") : base64EncodeFileName(fileName);
// 2. 设置下载窗口 -> Content-Disposition
response.setHeader("Content-Disposition", "attachment;filename=" + newFileName);
IO读写(写-响应给浏览器)
// 3. IO读写文件: 读出服务器文件,响应写入到浏览器
String path = request.getServletContext().getRealPath("upload") + File.separator + fileName;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] bs = new byte[8*1024];
int size = -1;
while ((size = bis.read(bs)) != -1) {
bos.write(bs, 0, size);
}
bis.close();
bos.close();
String path = request.getServletContext().getRealPath("upload") + File.separator + fileName;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
byte[] bs = new byte[8*1024];
int size = -1;
while ((size = bis.read(bs)) != -1) {
bos.write(bs, 0, size);
}
bis.close();
bos.close();
下载文件名中文乱码问题
不同浏览器编码方式不同:对文件名进行编码时以谷歌为代表的是 utf-8,其他浏览器是 base64
根据浏览器在下载窗口前设置编码方式
String userAgent = request.getHeader("User-Agent");
String newFileName = userAgent.contains("Chrome") ? URLEncoder.encode(fileName, "utf-8") : base64EncodeFileName(fileName);
response.setHeader("Content-Disposition", "attachment;filename=" + newFileName);
String newFileName = userAgent.contains("Chrome") ? URLEncoder.encode(fileName, "utf-8") : base64EncodeFileName(fileName);
response.setHeader("Content-Disposition", "attachment;filename=" + newFileName);
base64编码
public String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF‐8?B?"
+ new String(base64Encoder.encode(fileName.getBytes("UTF-8")))
+ "?=";
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF‐8?B?"
+ new String(base64Encoder.encode(fileName.getBytes("UTF-8")))
+ "?=";
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
正则表达式
概述
用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串。即一种规则,有自己特殊的应用。
作用
1. 匹配
测试字符串内的模式。例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
2. 替换
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
3. 提取
基于模式匹配从字符串中提取子字符串,可以查找文档内或输入域内特定的文本。
测试字符串内的模式。例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
2. 替换
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
3. 提取
基于模式匹配从字符串中提取子字符串,可以查找文档内或输入域内特定的文本。
方法和类
String 成员方法:
boolean matches(String regex); // 正则匹配
String[] split(String regex); // 正则分割
String replaceFirst(String regex, String replacement); // 正则替换第1个
String replaceAll(String regex, String replacement); // 正则替换所有
boolean matches(String regex); // 正则匹配
String[] split(String regex); // 正则分割
String replaceFirst(String regex, String replacement); // 正则替换第1个
String replaceAll(String regex, String replacement); // 正则替换所有
Pattern 类
Matcher 类
Matcher 类
Pattern 类:
public static Pattern compile(String regex); // 编译正则
public Matcher matcher(CharSequence input); // 匹配正则对象
Matcher 类:
boolean find() // 查找匹配子串
String group() // 返回匹配子串
String replaceAll(String replacement) // 替换所有
String replaceFirst(String replacement) // 替换第一个
public static Pattern compile(String regex); // 编译正则
public Matcher matcher(CharSequence input); // 匹配正则对象
Matcher 类:
boolean find() // 查找匹配子串
String group() // 返回匹配子串
String replaceAll(String replacement) // 替换所有
String replaceFirst(String replacement) // 替换第一个
匹配用法
String reg = "[a]{3}";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher("aaa");
boolean b = matcher.matches();
System.out.println(b); // true
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher("aaa");
boolean b = matcher.matches();
System.out.println(b); // true
提取用法
String s = "18937162148...safsdfa.f.ds.afsdf18566206696a651sdfas18937111765";
String reg = "[1]{1}[356789]{1}\\d{9}";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(s);
List<String> phones = new ArrayList<>();
// find() 查找匹配的子字符串
while (matcher.find()) {
// group() 返回匹配的子字符串
phones.add(matcher.group());
}
System.out.println(phones);
String reg = "[1]{1}[356789]{1}\\d{9}";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(s);
List<String> phones = new ArrayList<>();
// find() 查找匹配的子字符串
while (matcher.find()) {
// group() 返回匹配的子字符串
phones.add(matcher.group());
}
System.out.println(phones);
正则规则
单字符类
● `[abc]` a/b/c任意1个
● `[^abc]` 除了a/b/c的任何字符
● `[a-zA-Z]` a到z或A到Z含边界字符
● `[0-9]` 0-9之间的字符都包括
● `[^abc]` 除了a/b/c的任何字符
● `[a-zA-Z]` a到z或A到Z含边界字符
● `[0-9]` 0-9之间的字符都包括
预定义字符类/元字符
● `.` 任意1个字符
● `\d` 单个数字 [0-9]
● `\D` 非数字 [^0-9]
● `\w` 单词字符 [a-zA-Z_0-9]
● `\W` 非单词字符 [^\w]
● `\s` 空白字符 [\t\n\x0B\f\r]
● `\S` 非空白字符 [^\s]
● `\d` 单个数字 [0-9]
● `\D` 非数字 [^0-9]
● `\w` 单词字符 [a-zA-Z_0-9]
● `\W` 非单词字符 [^\w]
● `\s` 空白字符 [\t\n\x0B\f\r]
● `\S` 非空白字符 [^\s]
数量词
X 表示一个字符或者预定义字符
● `X?` 0或1次
● `X*` 0到n次
● `X+` 1到n次
● `X{n}` n次
● `X{n,}` 至少n次
● `X{n,m}` 至少n次,不超过m次
● `X?` 0或1次
● `X*` 0到n次
● `X+` 1到n次
● `X{n}` n次
● `X{n,}` 至少n次
● `X{n,m}` 至少n次,不超过m次
JavaScript
概述
概念
一门客户端脚本语言。
作用
可以用来增强用户和 html 页面的交过过程,可以控制 html 元素,让页面有一些动态的效果,增强用户体验。
发展
1992,Nombase开发,用于表单校验,ScriptEase
1995,Netscape(网景)开发LiveScript,SUN公司更名JavaScript
1997,ECMA协会制定标准ECMAScript,统一了所有客户端脚本语言的编码方式
总结:JavaScript = ECMAScript + JavaScript(BOM+DOM)
1995,Netscape(网景)开发LiveScript,SUN公司更名JavaScript
1997,ECMA协会制定标准ECMAScript,统一了所有客户端脚本语言的编码方式
总结:JavaScript = ECMAScript + JavaScript(BOM+DOM)
输出
- 使用 window.alert() 弹出警告框。
- 使用 document.write() 方法将内容写到 HTML 文档中。
- 使用 innerHTML 写入到 HTML 元素。
- 使用 console.log() 写入到浏览器的控制台。
使用 console.log() 方法在浏览器中显示 JavaScript 值。
F12 启用调试模式, 在调试窗口中点击 "Console" 菜单。
console.log()的用处:
主要是方便你调式javascript用的, 你可以看到你在页面中输出的内容。
相比alert他的优点是:
他能看到结构化的东西,如果是alert,弹出一个对象就是[object object],但是console能看到对象的内容。
console不会打断你页面的操作,如果用alert弹出来内容,那么页面就死了,但是console输出内容后你页面还可以正常操作。
console里面的内容非常丰富,你可以在控制台输入 console.log("hello,javascript")
F12 启用调试模式, 在调试窗口中点击 "Console" 菜单。
console.log()的用处:
主要是方便你调式javascript用的, 你可以看到你在页面中输出的内容。
相比alert他的优点是:
他能看到结构化的东西,如果是alert,弹出一个对象就是[object object],但是console能看到对象的内容。
console不会打断你页面的操作,如果用alert弹出来内容,那么页面就死了,但是console输出内容后你页面还可以正常操作。
console里面的内容非常丰富,你可以在控制台输入 console.log("hello,javascript")
语法
使用
内部JS
定义<script>标签,标签内就是js代码
<head>
<title>ECMAScript和页面结合之内部结合</title>
<%--JS脚本内部结合--%>
<script>
console.log("js脚本111")
</script>
</head>
<title>ECMAScript和页面结合之内部结合</title>
<%--JS脚本内部结合--%>
<script>
console.log("js脚本111")
</script>
</head>
外部JS
定义<script>,通过src属性引入外部的js文件
<head>
<title>ECMAScript与页面结合之外部结合</title>
<script src="${pageContext.request.contextPath}/xxx.js">
/*外部结合方式后,script 标签内js代码无效*/
</script>
</head>
<title>ECMAScript与页面结合之外部结合</title>
<script src="${pageContext.request.contextPath}/xxx.js">
/*外部结合方式后,script 标签内js代码无效*/
</script>
</head>
注意
a. <script>可以定义在页面的任何地方,位置会决定执行顺序
b. <script>可以定义多个
b. <script>可以定义多个
注释
单行 //
多行 /* */
多行 /* */
类型
基本数据类型
- number:数字,整数/小数/NaN(一个不是数字的number类型)
- string:字符串,"hello" 'abc'
- boolean:true 和 false
- null:一个对象为空的占位符
- undefined:未定义,变量没有初始化时的初始值
引用数据类型
- 对象
基本对象:
Array / Boolean / Date / Number / String / RegExp / Functions(全局函数对象) / Math / Events
Array / Boolean / Date / Number / String / RegExp / Functions(全局函数对象) / Math / Events
Function对象
创建方法
var 方法名 = new Function("形式参数列表", "方法体");
变量
Java是强类型语言,JavaScript是弱类型语言。
语法
var 变量名 = 初始化值;
typeof
获取变量的类型。
<script>
console.log(typeof 123); // number
console.log(typeof "abc"); // string
console.log(typeof true); // boolean
console.log(typeof null); // object
console.log(typeof NaN); // number
console.log(typeof num); // undefined
console.log(typeof [1,2,3]);// object
console.log(typeof {"name":"Jerry", "age":20}); // object
</script>
console.log(typeof 123); // number
console.log(typeof "abc"); // string
console.log(typeof true); // boolean
console.log(typeof null); // object
console.log(typeof NaN); // number
console.log(typeof num); // undefined
console.log(typeof [1,2,3]);// object
console.log(typeof {"name":"Jerry", "age":20}); // object
</script>
运算符
- 一元:++ --
- 算术:+ - * / %
- 赋值:= += -=
- 比较:> < >= <= == ===(全等于)
- 逻辑:&& || !
- 三元:表达式 ? 值1 : 值2
- 流程:if-else switch-case while do-while for try-catch
比较方式:
1. 类型相同:直接比较,字符串按照字典顺序比较;
2. 类型不同:先进行类型转换,再比较;(=== 全等于,类型和值都比较,先判断类型,类型不同,直接返回false)
switch分支:
1. Java中 switch 可接收的数据类型:byte int short char 枚举(jdk1.5) String(jdk1.7);
2. JS中 switch 可接收的数据类型:任意JS中的基本数据类型
1. 类型相同:直接比较,字符串按照字典顺序比较;
2. 类型不同:先进行类型转换,再比较;(=== 全等于,类型和值都比较,先判断类型,类型不同,直接返回false)
switch分支:
1. Java中 switch 可接收的数据类型:byte int short char 枚举(jdk1.5) String(jdk1.7);
2. JS中 switch 可接收的数据类型:任意JS中的基本数据类型
注意事项
number:0或者NaN为 false,其他为 true
string:除了空字符串""为 false,其他为 true
null 和 undefined:都是 false
对象:所有对象都是 true
string:除了空字符串""为 false,其他为 true
null 和 undefined:都是 false
对象:所有对象都是 true
demo
a标签
<a href="#">跳转</a>
// 死链接,点击跳转时页面和链接不会发生变化
<a href="javascript:void(0)">跳转</a>
// 死链接,void中内容会执行但不会有任何返回
<a href="javascript:void(alert('Warning'))">跳转</a>
// 死链接,点击跳转时页面和链接不会发生变化
<a href="javascript:void(0)">跳转</a>
// 死链接,void中内容会执行但不会有任何返回
<a href="javascript:void(alert('Warning'))">跳转</a>
引用
Array 对象
demo
Date 对象
demo
RegExp 对象
/^正则表达式$/
demo
全局函数对象
parseInt() // 数字字符串转换为数字
isNaN() // 判断变量是否是NaN
eval() // 多用于转换json字符串为js对象,以调用属性
isNaN() // 判断变量是否是NaN
eval() // 多用于转换json字符串为js对象,以调用属性
<script>
// eval() 更多的用于 json 字符串返回 js 对象
var jsonStr = '{"username":"root", "password":"1234"}';
var obj = eval("(" + jsonStr + ")"); // 固定语法,将json字符串转换成js对象
console.log(obj.username + "," + obj.password);
</script>
// eval() 更多的用于 json 字符串返回 js 对象
var jsonStr = '{"username":"root", "password":"1234"}';
var obj = eval("(" + jsonStr + ")"); // 固定语法,将json字符串转换成js对象
console.log(obj.username + "," + obj.password);
</script>
demo
函数
三种方式
// 第一种方式
function method01(msg1, msg2, msg3) {
console.log(msg1 + ",", msg2 + "," + msg3);
// arguments: 属于方法的内置对象,包含的是实参
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
return "hello js function!";
}
// 调用
var returnValue1 = method01("a", "b", "c");
console.log(returnValue1);
function method01(msg1, msg2, msg3) {
console.log(msg1 + ",", msg2 + "," + msg3);
// arguments: 属于方法的内置对象,包含的是实参
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
return "hello js function!";
}
// 调用
var returnValue1 = method01("a", "b", "c");
console.log(returnValue1);
// 第二种方式
var method02 = function (msg1, msg2, msg3) {
console.log(msg1 + ",", msg2 + "," + msg3);
return "hello js function2";
};
// 调用
var returnValue2 = method02("d", "e", "f");
console.log(returnValue2);
var method02 = function (msg1, msg2, msg3) {
console.log(msg1 + ",", msg2 + "," + msg3);
return "hello js function2";
};
// 调用
var returnValue2 = method02("d", "e", "f");
console.log(returnValue2);
// 第三种方式 - 基本不用
var method03 = new Function("msg1, msg2, msg3", "console.log(msg1 + \",\", msg2 + \",\" + msg3); return \"hello js function3\";");
// 调用
var returnValue3 = method03("h", "i", "j");
console.log(returnValue3);
var method03 = new Function("msg1, msg2, msg3", "console.log(msg1 + \",\", msg2 + \",\" + msg3); return \"hello js function3\";");
// 调用
var returnValue3 = method03("h", "i", "j");
console.log(returnValue3);
JavaScript 支持 内嵌函数(类似于成员内部类)
JavaScript 闭包
<script>
/* JavaScript 闭包:能够访问父作用域中的变量,提高了局部变量的生命周期。*/
var add = (function () { //自执行的匿名函数
var count = 0; // 局部变量
return function () { // 内部函数, 把方法返回,赋值给了变量result
return count += 1; // 访问外部自执行函数的局部变量
}
})();
console.log(result()); // 1
console.log(result()); // 2
console.log(result()); // 3
</script>
/* JavaScript 闭包:能够访问父作用域中的变量,提高了局部变量的生命周期。*/
var add = (function () { //自执行的匿名函数
var count = 0; // 局部变量
return function () { // 内部函数, 把方法返回,赋值给了变量result
return count += 1; // 访问外部自执行函数的局部变量
}
})();
console.log(result()); // 1
console.log(result()); // 2
console.log(result()); // 3
</script>
JSON字符串
JavaScript Object Notation 一种轻量级的数据交换格式。
易于阅读和编写,同时易于机器解析和生成(网络传输速率)。
易于阅读和编写,同时易于机器解析和生成(网络传输速率)。
同步请求中,数据从后台到前端,需要将数据对象存储在 域对象 中;
异步请求中,数据从后台到前端,需要将数据对象转换为 JSON 字符串。
根据 JavaBean 对象生成对应的 JSON 字符串。
异步请求中,数据从后台到前端,需要将数据对象转换为 JSON 字符串。
根据 JavaBean 对象生成对应的 JSON 字符串。
JavaBean 有单一对象,容器对象,JSON对单一对象和容器对象有不同的写法。
数据格式
一个数据
{"键1":值1, "键2":值2}
一组数据
[{"键1":值1, "键2":值2}, {"键1":值1, "键2":值2}]
Java中转换
FastJSON、Jackson、Gson
性能对比分析
FastJson
fastjson-1.2.62.jar
对象 >>> json字符串
// 可转对象/list/map >> json
User user = new User("root", "1234");
String jsonStr = JSON.toJSONString(user);
User user = new User("root", "1234");
String jsonStr = JSON.toJSONString(user);
json字符串 >> 对象
// 可转json字符串 >> 为java对象/list/map
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = JSON.parseObject(jsonStr, User.class);
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = JSON.parseObject(jsonStr, User.class);
Jackson
jackson-annotations-2.9.9.jar
jackson-core-2.9.9.jar
jackson-databind-2.9.9.jar
jackson-core-2.9.9.jar
jackson-databind-2.9.9.jar
ObjectMapper objectMapper = new ObjectMapper();
对象 >> json字符串
// 可转对象/list/map >> json
User user = new User("root", "1234");
String jsonStr = objectMapper.writeValueAsString(user);
User user = new User("root", "1234");
String jsonStr = objectMapper.writeValueAsString(user);
json字符串 >> 对象
// 可转json字符串 >> 为java对象/list/map
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = objectMapper.readValue(jsonStr, User.class);
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = objectMapper.readValue(jsonStr, User.class);
Gson
gson.jar
Gson gson = new Gson();
对象 >> json字符串
// 可转对象/list/map >> json
User user = new User("root", "1234");
String jsonStr = gson.toJson(user);
User user = new User("root", "1234");
String jsonStr = gson.toJson(user);
json字符串 >> 对象
// 可转json字符串 >> 为java对象/list/map
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = gson.fromJson(jsonStr, User.class);
String jsonStr = "{'username':'root', 'password':'1234'}";
User user = gson.fromJson(jsonStr, User.class);
JavaScript中转换
<script>
// 方式一:JSON.stringify() JSON.parse()
var user = {"username": "root", "password": "1234"};
// JS >> JSON
var str = JSON.stringify(user);
alert(str);
// JSON >> JS
var js = JSON.parse(str);
alert(js.username + ", " + js.password);
</script>
// 方式一:JSON.stringify() JSON.parse()
var user = {"username": "root", "password": "1234"};
// JS >> JSON
var str = JSON.stringify(user);
alert(str);
// JSON >> JS
var js = JSON.parse(str);
alert(js.username + ", " + js.password);
</script>
<script>
// 方式二:eval() 更多的用于 json 字符串返回 js 对象
var jsonStr = '{"username":"root", "password":"1234"}';
var obj = eval("(" + jsonStr + ")"); // 固定语法,将json字符串转换成js对象
console.log(obj.username + "," + obj.password);
</script>
// 方式二:eval() 更多的用于 json 字符串返回 js 对象
var jsonStr = '{"username":"root", "password":"1234"}';
var obj = eval("(" + jsonStr + ")"); // 固定语法,将json字符串转换成js对象
console.log(obj.username + "," + obj.password);
</script>
事件
事件参考手册
触发条件
事件源:html标签
监听器:js方法
绑定/注册:标签中的属性赋值
事件:具体的操作
监听器:js方法
绑定/注册:标签中的属性赋值
事件:具体的操作
<%--事件源 + 绑定方式①--%>
// 监听器
function fn1() {
console.log("按钮1点击了...");
}
...
<button onclick="fn1()">事件按钮1</button>
// 监听器
function fn1() {
console.log("按钮1点击了...");
}
...
<button onclick="fn1()">事件按钮1</button>
<%--事件源 + 绑定方式②--%>
// 获取 id 为 btn 的标签对象
var ele = document.getElementById("btn");
// fn2 使用方式 ① -- 最佳
ele.onclick = function () {
console.log("按钮2点击了...");
}
...
<button id="btn">事件按钮2</button>
// 获取 id 为 btn 的标签对象
var ele = document.getElementById("btn");
// fn2 使用方式 ① -- 最佳
ele.onclick = function () {
console.log("按钮2点击了...");
}
...
<button id="btn">事件按钮2</button>
<%--事件源 + 绑定方式②--%>
// 获取 id 为 btn 的标签对象
var ele = document.getElementById("btn");
// fn2 使用方式 ② - 不推荐
function fn2() {
console.log("按钮2点击了...");
}
ele.onclick = fn2;
...
<button id="btn">事件按钮2</button>
// 获取 id 为 btn 的标签对象
var ele = document.getElementById("btn");
// fn2 使用方式 ② - 不推荐
function fn2() {
console.log("按钮2点击了...");
}
ele.onclick = fn2;
...
<button id="btn">事件按钮2</button>
监听事件
加载
onload
页面或图像加载完成
图像
function fn1() {
console.log("这是个图片。。");
}
...
<img src="img/girl.jpg" onload="fn1()">
console.log("这是个图片。。");
}
...
<img src="img/girl.jpg" onload="fn1()">
页面
// 如果使用 dom 分配事件,推荐该方式(获取标签id的js代码可写在页面上方)
// 监听页面加载完成后的操作
window.onload = function () {
console.log("页面加载完成");
var ele = document.getElementById("girl");
ele.onclick = function () {
console.log("我正在疯狂的点击图片...");
}
}
...
<img id="girl" src="img/girl.jpg">
// 监听页面加载完成后的操作
window.onload = function () {
console.log("页面加载完成");
var ele = document.getElementById("girl");
ele.onclick = function () {
console.log("我正在疯狂的点击图片...");
}
}
...
<img id="girl" src="img/girl.jpg">
onunload
用户退出页面
onabort
图像加载被中断
onerror
当加载文档或图像时发生某个错误
焦点
onfocus
元素获得焦点
<script>
function fn1() { console.log("1 获取焦点"); }
function fn2() { console.log("2 失去焦点"); }
function fn3() { console.log("3 获取焦点"); }
function fn4() { console.log("4 失去焦点"); }
</script>
<input type="text" onfocus="fn1()" onblur="fn2()"> <br>
<input type="text" onfocus="fn3()" onblur="fn4()">
function fn1() { console.log("1 获取焦点"); }
function fn2() { console.log("2 失去焦点"); }
function fn3() { console.log("3 获取焦点"); }
function fn4() { console.log("4 失去焦点"); }
</script>
<input type="text" onfocus="fn1()" onblur="fn2()"> <br>
<input type="text" onfocus="fn3()" onblur="fn4()">
onblur
元素失去焦点
鼠标
onclick
鼠标单击某个对象
ondblclick
鼠标双击某个对象
onmousedown
鼠标的按键被按下
<script>
function fn1() { console.log("鼠标按下"); }
function fn2() { console.log("鼠标移动"); }
function fn3() { console.log("鼠标松开"); }
</script>
<body onmousedown="fn1()" onmousemove="fn2()" onmouseup="fn3()">
function fn1() { console.log("鼠标按下"); }
function fn2() { console.log("鼠标移动"); }
function fn3() { console.log("鼠标松开"); }
</script>
<body onmousedown="fn1()" onmousemove="fn2()" onmouseup="fn3()">
onmouseup
鼠标的按键被松开
onmousemove
鼠标移动
onmouseover
鼠标移到某个元素上
onmouseout
鼠标从某个元素移开
键盘
onkeydown
键盘的键被按下
<script>
function fn1() { console.log(event.keyCode + " 键盘按下 "); }
function fn2() { console.log(event.keyCode + " 键盘松开 "); }
</script>
<input type="text" onkeydown="fn1()" onkeyup="fn2()">
function fn1() { console.log(event.keyCode + " 键盘按下 "); }
function fn2() { console.log(event.keyCode + " 键盘松开 "); }
</script>
<input type="text" onkeydown="fn1()" onkeyup="fn2()">
onkeypress
键盘的键被按下或按住
onkeyup
键盘的键被松开
按钮
onreset
重置按钮被点击
onsubmit
提交按钮被点击
<script>
function fn1() {
console.log("表单提交了...");
var num = 1; // 数据校验
if (num === 1) { return true; // 不拦截表单 } else { return false; // 拦截表单提交 }
}
</script>
<%-- return fn1() --%>
<form action="index.jsp" onsubmit="return fn1()">
消息:<input type="text" name="message"> <br>
<button type="submit">发送</button>
</form>
function fn1() {
console.log("表单提交了...");
var num = 1; // 数据校验
if (num === 1) { return true; // 不拦截表单 } else { return false; // 拦截表单提交 }
}
</script>
<%-- return fn1() --%>
<form action="index.jsp" onsubmit="return fn1()">
消息:<input type="text" name="message"> <br>
<button type="submit">发送</button>
</form>
其他
onchange
用户改变了内容
<script>
function fn1() { console.log("内容发生改变"); }
function fn2() { console.log("选项发生改变..."); }
</script>
<input type="text" onchange="fn1()">
<select onchange="fn2()">
<option>选项1</option>
<option>选项2</option>
<option>选项3</option>
</select>
function fn1() { console.log("内容发生改变"); }
function fn2() { console.log("选项发生改变..."); }
</script>
<input type="text" onchange="fn1()">
<select onchange="fn2()">
<option>选项1</option>
<option>选项2</option>
<option>选项3</option>
</select>
onselect
文本被选定
onresize
窗口或框架被调整尺寸
BOM 对象
Browser Object Model,浏览器对象模型
window 对象
属性
可以通过 window 对象获取其他4个BOM对象
- document 对 Document 对象的只读引用。
- history 对 History 对象的只读引用。
- location 用于窗口或框架的 Location 对象。可以设置页面跳转路径
- Navigator 对 Navigator 对象的只读引用。
- Screen 对 Screen 对象的只读引用。
方法
- alert(message) 显示带有一段消息和一个确认按钮的警告框。
- confirm(message) 显示带有一段消息以及确认/取消对话框。
- prompt([text], [defaultText]) 显示可提示用户输入对话框。
- close() 关闭浏览器窗口 - 必须是新开的页面窗口才能关闭。
- clearInterval(重复对象) 清除由 setInterval() 设置的调用。
- clearTimeout(延迟对象) 清除由 setTimeout() 方法设置的调用。
- setInterval(code, millisec[, "lang"]) 按照间隔的周期(毫秒)来调用函数或计算表达式。返回值是重复对象
- setTimeout(code, millisec) 在延迟毫秒数后调用函数或计算表达式。返回值是延迟对象
demo
navigator 对象
screen 对象
history 对象
属性
- length 返回浏览器历史列表中的 URL 数量。
方法
- back() 加载 history 列表中的前一个 URL。
- forward() 加载 history 列表中的下一个 URL。
- go() 加载 history 列表中的某个具体页面。
demo
location 对象
属性
- hash 设置或返回从井号 (#) 开始的 URL(锚)。
- host 设置或返回主机名和当前 URL 的端口号。
- hostname 设置或返回当前 URL 的主机名。
- href 设置或返回完整的 URL。
- pathname 设置或返回当前 URL 的路径部分。
- port 设置或返回当前 URL 的端口号。
- protocol 设置或返回当前 URL 的协议。
- search 设置或返回从问号 (?) 开始的 URL(查询部分)。
方法
- assign() 加载新的文档。
- reload() 重新加载当前文档。
- replace() 用新的文档替换当前文档。
demo
XML DOM
核心 DOM 模型:document + element + node
document 文档对象
element 元素对象
node 节点对象
HTML DOM
HTML DOM 定义了访问和操作 HTML 文档的标准方法。
HTML DOM 把 HTML 文档呈现为带有元素、属性和文本的树结构(节点树)。
HTML DOM 把 HTML 文档呈现为带有元素、属性和文本的树结构(节点树)。
innerHTML / innerText
使用 HTML 元素对象的属性
控制元素样式
JS:综合案例
获取 select 下所有的 option 中的文本信息
获取 select 下选中的 option 中的文本信息和 value 属性的值
在 select 下增加一个选项
全选 & 全不选 & 反选
正则校验的注册表单
Ajax
基本信息
概述
Asynchronous Javascript And XML,异步 JavaScript 和 XML,一种创建交互式网页应用的网页开发技术。
原理
通过在后台与服务器进行少量数据交换,AJAX可以是网页实现异步更新。
这意味着可以在不重新加载整个网页的情况下,对网页的部分内容进行更新。
(普通不适用AJAX的网页如果需要更新则必须刷新整个页面内容)
这意味着可以在不重新加载整个网页的情况下,对网页的部分内容进行更新。
(普通不适用AJAX的网页如果需要更新则必须刷新整个页面内容)
作用
1. 可以刷新局部页面内容
2. 可以发起异步请求
2. 可以发起异步请求
异步&同步请求
- 同步请求:当页面内容发生改变时,必须全部刷新,且刷新的时候不能发出其他请求。
- 异步请求:可以局部改变网页的内容,当正在发生改变时,其他的模块内容也可以发出请求。
XMLHttpRequest 对象
ajax异步请求对象。
流程
典型的xhr建立ajax的过程:
1、new一个xhr对象;
2、调用xhr对象的open方法;
3、send一些数据;
4、对服务器的响应过程进行监听,来知道服务器是否正确得做出了响应,接着就可以做一些事情。比如获取服务器响应的内容,在页面上进行呈现。
1、new一个xhr对象;
2、调用xhr对象的open方法;
3、send一些数据;
4、对服务器的响应过程进行监听,来知道服务器是否正确得做出了响应,接着就可以做一些事情。比如获取服务器响应的内容,在页面上进行呈现。
创建
function createXMLHttpRequest() {
var xmlHttp;
try {
// IE7+, Chrome, Firefox, Opera 8.0+, Safari 主流浏览器
xmlHttp = new XMLHttpRequest();
} catch (e) {
try {
// IE6, IE5 浏览器
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
// 其他浏览器
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
// Nothing to do.
}
}
}
return xmlHttp;
}
var xhr = createXMLHttpRequest();
var xmlHttp;
try {
// IE7+, Chrome, Firefox, Opera 8.0+, Safari 主流浏览器
xmlHttp = new XMLHttpRequest();
} catch (e) {
try {
// IE6, IE5 浏览器
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
// 其他浏览器
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
// Nothing to do.
}
}
}
return xmlHttp;
}
var xhr = createXMLHttpRequest();
属性
onreadystatechange, 用于指定XMLHttpRequest对象状态改变时的事件处理函数
响应
status / statusText:以数字/文本形式返回http状态码
readyState, XMLHttpRequest对象的处理状态,响应返回成功的时候得到通知
- 0 :请求未初始化,open还没有调用
- 1 :服务器连接已建立,open已经调用了
- 2 :请求已经接收,也就是接收到头信息了
- 3 :请求处理中,也就是接收到响应主体了
- 4 :请求已完成,且响应已就绪,也就是响应完成了
* 当 status === 200 && readyState === 4 时才去读取响应数据。
responseText / responsXML:获得字符串/XML形式的相应数据
getAllResponseHeader():获取所有的响应报头
getResponseHeader():查询响应中的某个字段的值
方法
open, 打开链接
open(请求方式, 请求路径, flag); // flag==true 异步请求, false 同步请求
setRequestHeader, 设置请求头
setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
模拟form表单,专用于POST请求
send, 发送数据
send(数据);
GET请求,send 方法不需要携带参数,直接将参数拼接在 open 方法的路径后面
POST 请求,需要 send 方法带参来发送
POST 请求,需要 send 方法带参来发送
异步 GET/POST请求
GET 请求
demo
POST 请求
demo
注意事项
在以下情况中,请使用 POST 请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
CodePart
Java
枚举
四舍五入
Stream流
Thread
MySQL
0 条评论
下一页