赞
踩
前端知识
框架
javaSE:韩顺平900.
Spring:黑马程序员新版Spring零基础入门到精通,一套搞定spring全套视频教程(含实战源码)_哔哩哔哩_bilibili
MyBatis:尚硅谷MyBatis实战教程全套完整版(初学者零基础从入门到精通,好评如潮,资料齐全)_哔哩哔哩_bilibili
MyBatisPlus:尚硅谷MyBatisPlus教程(mybatis-plus框架精讲)_哔哩哔哩_bilibili
Maven:黑马程序员Maven全套教程,maven项目管理从基础到高级,Java项目开发必会管理工具maven_哔哩哔哩_bilibili
SpringBoot2:【尚硅谷】SpringBoot2零基础入门教程(spring boot2干货满满)_哔哩哔哩_bilibili
SpringSecurity:尚硅谷SpringSecurity框架教程(spring security源码剖析从入门到精通)_哔哩哔哩_bilibili
Mysql:黑马程序员 MySQL数据库入门到精通,从mysql安装到mysql高级、mysql优化全囊括_哔哩哔哩_bilibili
Redis:黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目_哔哩哔哩_bilibili
消息队列:Kafka、ActiveMQ、TubeMQ、RocketMQ
微服务。
容器Docker。
K8S
CI/CD
常用类库
JDK编程环境
JRE运行环境
JVM运行软件
JRE运行环境
bin目录是开发工具
lib依赖包
src源码
db是jdk自带数据库
include是C和C++开发JDK所用的头文件
demo例子
方便DOS命令调用lib中的命令【命令对应:命令 -help】
项目
包
类等
字段等
规则
字母,数字,下划线,美元符为元素
不能是关键字
不能是数字开头
规范
包名全小写
类名,接口名大驼峰
变量名,方法名小驼峰
常量名,全大写下划线连接
使用
声明
赋值
四类八种
整数Long要使用L
浮点数Folat要使用F,是近似值
字符输出Unicod编码
布尔只能是两种值
左右是数值是加法
左右有字符串是拼接
ASCII统一一个字节
Unicode统一两个字节【java的字符编码】
UTF-8字母一个字节,汉字三个字节
GBK字母一个字节汉字两个字节
gb2312可以表示汉字
big5可繁体中文
不同类型之间的计算
两条自动转换线
整数到浮点数转换中只有int到double不会丢失精度
【非自动转换就是强转,会丢失精度或溢出】
转成字符串
字符串相加拼接成字符
转成基本类型
Integer.parseInt()解析成Int
字符从字符串下标获取就行
解析成基本类型必须保证类型正确
单目:+,-,*,/,%
双目:++,--
三目:boolean ? value1 : value2
关系:==,!=,<,>,<=,>=,instanceof
逻辑:&&,&,||,|,!,^
赋值:=,单目=
二进制
八进制
十进制
十六进制F
正数三码合一,负数
源码
反码:源码保留符号位其他全部取反
补码:反码加一
位运算
<<左移
<<右移
>>>无符号右移
~取反
&与
|或
^异或
顺序:向前引用
分支:if...else。switch...case...default【break防止穿透】。
循环:for。while。do...while。
break:跳出循环
continue:跳出本次循环
return:跳出方法
该数据类型解决单个数据存放问题,多个相同数据方便使用。
特点
定长
连续下标
存储相同元素
使用
声明
开辟空间
初始化
下标取元素
方法区:类加载信息
栈:执行方法
堆:存放对象
常量池:存放字符串,或final常量
new本类
new子类
使用类的静态成员
反射
继承的所有属性都在一个对象中。
解决字节码加载到内存开始,到Class类对象创建
加载:加载字节码到内存【方法区】【并且创建类对象】
连接
验证:验证内存中的字节码【格式,数据,字节码,符号引用】
准备:静态变量默认初始化
解析:常量池中的符号引用替换成直接引用
初始化:开始静态初始化
【-Xverify:none:关闭大部分验证】
类加载过程【先加载父类对象】
静态属性默认初始化
静态属性显示初始化:属性直接初始化和静态代码块初始化按照顺序来。
实例化对象【先加载父类对象】
属性初始化
属性显示初始化:属性直接初始化和代码块初始化按照顺序来。
构造方法初始化
赋值给引用
指定初始化
静态属性存储。说法一:静态属性在方法区的静态域。说法二:静态属性是创建的class对象中。
类
属性
方法
构造函数
包
封装
继承
多态
静态
代码块
该数据类型解决数组问题,有类型,有名称,可以使用函数。
解决类型的定义。
属性
方法
构造器
代码块
内部类
使用
实例化
初始化
对象操作属性和方法
类数据类型中的元素。
特点
有访问修饰符
有默认值
解决执行代码可重用问题。
特点
有访问修饰符
有返回值
有方法名
有参数
方法声明返回值可以是任意类型或void
return返回具体返回值或跳出方法
可以有,可以没有
调用的时候传参兼容【兼容,个数,顺序】
【传参机制】
解决同源的复杂问题,将大问题一步步拆分成为一个最简单的问题。
方法自己调用自己
解决功能和名称映射问题,同功能的方法名称保持一致。
方法名相同
形参列表不一致【类型,个数,顺序】
解决不确定参数个数的问题,将任意个同类型参数的方法封装成一个方法。
可变参必须放在形参列表最后
可变参只能出现一个
传参可以是数组也可以是多个同类型参数
解决数据的生命,节省存储数据的空间
全局变量:
普通属性作用域是对象,静态属性作用域是类。
有访问修饰符
有默认值
生命等同对象
局部变量:
所在代码块中
生命等同方法
全局变量和局部变量可以同名
解决对象实例化问题,同时有参构造还可以初始化。
有访问修饰符
没有返回值
构造器方法名等同于类名
没有任意一个构造器的时候会给一个无参构造
构造器由JVM系统调用
构造器可以重载
解决本类属性和参数同名时,指向本类属性。
本质this指向本对象
指属性
指方法
指构造
解决相同类名的问题,管理类。
package表示所在包
import表示引入的包或类
使用引入两个同名类的时候,需要权限的类名指定
命名规则:com+公司名+项目名+业务模块
解决方法和属性的访问权限问题。
public公开
protected受保护,同类同包或子类
default同类同包
private本类
解决类中的属性设置和获取时加上一层过滤。
将属性和操作属性的方法封装在一起
操作属性的时候加一层过滤
使用
属性私有化
设置和获取方法
构造器参与封装
解决创建对象的时候没有一层过滤
构造器初始化时调用对应set方法
解决重复定义类的问题。
访问修饰符决定属性和方法继承或不继承
子类必须调用父类的构造器,完成父类初始化.
所有子类默认调用父类无参构造器
显示调用父类构造器要放在子类构造器的第一行代码
this和super都只能放在构造器第一行代码,不能共存
所有类都是Object的子类
一个类只能有一个父类
所有类都可以调用Object类的方法
继承需要保持IS-A的关系
查找机制
从子类向Object去找
找到不可以访问的就会报错
解决继承中子类访问父类的对象信息。
父类可访问属性
父类可访问方法
父类可访问构造
【表示父类对象】
解决继承中,子类覆盖父类的方法。
方法名相同
形参列表相同
访问权限比父类大
返回值比范围父类小
解决不确定具体类型,用统一类型表示具体类型。
解决相同的方法名,调用出来不同的功能实现。
方法重载:根据不同的参数决定
方法重载:对象不一样就调用不一样的方法
对象引用类型不能修改,也就是编译类型不能修改
父类引用可以指向子类对象
解决父类引用类型指向子类运行类型。
父类引用指向子类实现
只能访问父类的属性和方法
以及子类的重写方法
解决父类类型不能调用子类特有方法。
子类引用强制指向父类引用【类型强制转换】
编译类型和运行类型一致,就等同于创建一个子类
多态数组
多态参数
解决继承中所有的方法查找,从实现类开始查找。
方法有动态绑定,从具体实现开始查找方法实现。
属性没有动态绑定,从引用类型开始查找。
解决所有类的父类,提供最基础的方法。
equals比较对象地址【==还可以判断基本类型的值】常重写判断内容
getClass运行时类型
finalize回收没有引用的对象时调用该方法【System.gc主动回收】
hashCode对象hash值【集合处重写】
toString对象字符串表示【全类名+@+hash十六进制值】常重写打印内容【输出对象默认调用】
解决代码运行类型源码查看,看代码原理或排错。
F7跳入
F8跳过
F9下一个断点
shift+F7强制跳入
shift+F8跳出
解决类所持有的属性,方法
修饰属性:是类变量,可以和访问修饰符顺序颠倒
修饰方法:是类方法,可以和访问修饰符顺序颠倒
解决所有同类对象的共同属性。
对象名和类名都可以调用
所有同类对象共享属性
【静态属性和属性的区别只有对象共享的区别】
解决不创建对象直接调用方法。
对象名和类名都可以调用
【静态方法和普通方法的区别静态方法只能调用静态成员】
解决JVM调用方法的入口。
public:虚拟机不总是和main方法同包
static:虚拟机调用main方法不必创建对象
void:虚拟机在获取返回值的时候程序就结束了
main:虚拟机默认找到的入口方法标签
args:虚拟机执行main方法所需要的命令
IDEA参数传递:program arguments
解决类,对象初始化问题
静态代码块:给静态属性赋值,或者
普通代码块:抽取构造器的前面公共代码
解决全局只有一个该类的对象。
饿汉式:创建好一个实例给静态属性,等待使用静态方法去获取
懒汉式:第一次使用静态方法获取实例的时候才创建对象
各自特点
加载时机:饿汉式类加载的时候就创建,懒汉式调用方法的时候才创建。
线程安全:饿汉式是线程安全的,懒汉式线程不安全。
资源问题:饿汉式可能会一次都没有使用,懒汉式不会有资源浪费问题。
解决类,方法,属性,局部变量的使用限制。
类:不能被继承
方法:不能被重写
属性:只能初始化一次【常量】
局部变量:只能赋值一次
构造器不能被final修饰,构造器本就不能被继承。
final类一定全是final方法,final方法的类不一定是final类。
final配合static:类不会被加载【没有顺序要求】
解决继承中,父类的方法只给方法定义不给实现的抽象方法。
抽象类只能被继承不能被实例化。
抽线方法只能被重写。
抽象方法一定在抽象类中,但是抽象类中不一定有抽象方法。
只有实现类实现了抽线类的所有抽象方法,才能实例化。
解决实现类的规范。
定义
接口只能是public或者default。和类的访问修饰符一样
所有的属性都是静态常量。【public默认】
所有方法都是抽象方法。【public默认】
接口是LIKE-A的关系
实现
实现类实现接口,必须实现所有的抽象方法。
抽象类实现接口,可以保留抽象方法。
接口可以被接口或实现类或抽象类多实现。
接口多态
可以和对象多态一样使用在多态数组,和多态参数上。
多态传递,方法需要被重写,传递到实现类去重写。
JDK7:可以有静态方法和默认方法
JDK8:可以有私有方法
解决类的单继承问题。
局部内部类
地位是局部变量
修饰该类的修饰符和修饰局部变量一样
局部内部类直接访问外部类成员
作用域下外部类创建对象之后再访问内部类
作用域是所在方法
内部类调用外部类重名成员(调用外部类:外部类名+this+成员)
匿名内部类
同局部内部类的区别
是一个没有名称的类【名称:外部类名$数字】
还是一个构造器创建的对象
成员内部类
地位是普通属性
修饰该类的修饰符和修饰普通属性一样
成员内部类直接访问外部类成员
作用域下外部内创建对象再访问内部类
作用域是所在对象
内部类调用外部类重名成员(调用外部类:外部类名+this+成员)
静态成员内部类
地位是静态属性
修饰该类的修饰符和修饰普通属性一样
静态内部类直接访问外部类静态成员
作用域下外部内创建对象再访问内部类
作用域是所在类对象
解决存放有限特定的对象问题
普通类实现枚举
构造器私有化
去掉set方法
创建实例给静态常量
枚举类
默认继承Enum类
枚举类型默认是静态常量,创建的对象
【枚举类有枚举对象,隐式继承Enum以外就是一个普通类】
解决给代码提供解释信息,配置书写的一种形式。
继承Annotation接口。
定义时就是定义一个抽象方法,可以给默认值。
使用直接给方法名赋值。
元注解
@Target使用目标位置【类,属性,方法,参数,构造函数,局部变量,注解,包,类型参数,类型使用】
@Retention:注解声明周期【源码,字节码,运行时】
@Documented:可以作为文档
@Inherited:可以被继承
解决出现异常的时候程序任然能继续运行。
抛出的异常信息系统会封装成对应的异常
具体异常类
异常相关信息
异常追踪
处理
catch捕获异常
throws或throw抛出异常【默认throws】抛给方法调用处
catch
没有出现异常不会进入catch
出现异常try后面代码不运行直接进入catch
catch可以有多个从上往下一一匹配【父类在下面】
finally
无论出不出现异常都会执行
return
return最后出现在哪里就会返回哪里的值
自定义异常
继承异常类
将异常信息向父类调用
解决基本类型没有对应的处理方法
八种基本数据类型对应的引用类型
int基本数据类型对应Integer引用类型
char基本数据类型对应Character引用类型
解决包装类型的使用。
JDK1.5自动拆箱装箱:直接将相关类型进行赋值。【底层是valueOf和intValue】
拆箱:intValue
装箱:Integer.valueOf【在构造函数上加了一个字节的数字缓存】
解决基本类型或包装类型和字符串的关联。
转成包装类
Integer的构造方法【底层调用对应的parse类型方法,character类型直接使用String的charAt方法】
转成字符串
String类的valueOf【数值类型调用的是对应的toString方法,boolean是判断true或false,字符是使用字符数组创建字符串】
数值加上双引号【底层还是toString】
解决缓存int类型一个字节使用最频繁的数字,来提高速度。
Integer包装类的valueOf方法有一个字节的缓存。
只要有基本数据类型==判断的是值是否相等
解决字符序列的保存,本质是类中维护char数组常量。
创建
引号引起来【指向常量池】
new一个String类【先指向堆中String对象再指向常量池】
Intern方法
池中已经存在了就【指向常量池】
池中没有就new一个String类【指向常量池新创建的字符串常量】
解决用可变字char数组代替String对象数组。
StringBuufer保存的是临时char数组
真正保存数组的是抽象父类AbstractStringBuilder中的value
默认初始化StringBuffer的容量是16
添加一个空字符串会往里面加上null
容量不够扩容2被+2个容量,最大容量是Integer最大值
解决StringBuilder所有方法都没有StringBuffer上的锁。
解决数学运算的API。
正数类型的int和long
浮点类型的float和double
解决数组的操作工具类。
排序
自然排序
定制排序:传入Comparator接口实现类
解决系统相关信息的获取。
解决比较大的数计算。
范围更大的整数:BigInterger
高精度浮点数:BigDecimal
除法需要注意到除不尽的情况。
解决日期的使用。
Date和SimpleDateFormat
Calender
LocalDate
解决简单的日期获取设置,基于时区的毫秒数。
Date:获取当前时间毫秒数
SimpleDateFormat:格式化Date时间
构造参数是格式化的格式
format方法是将Date转成String
parse方法是将String类型解析成Date
解决日期的拆分,并且增删改问题,还可以修改时区
getInstance方法获取Calendar对象
使用get方法传入对应的参数【比如Calendar.YEAR】
解决日期的计算问题,丰富的API
优点
可变性:增删改
偏移量:Date从1900年开始
格式化:Calendar不能格式化
LocalDate:可以处理润秒【每隔两天多一秒】
时间API
LocalDate:日期【API】
LocalTime:时间【API】
LocalDateTime:日期时间【API】
now方法获取对象
get类型获取对应时间数据
格式化API
DateTimeFormatter类【API】
ofPattern方法定义格式
format(时间API)进行格式化
时间戳API
Instant类【API】
now方法获取时间戳
Date的from静态方法能将Instant转成Date
Date的toInstant方法能将Date转成Instant
解决存放Object类型。
解决单个值的集合。
迭代器:Collection集合实现了Iterable接口的都可以使用迭代器
增强for:集合和数组都可以使用增强for遍历
fori循环:list集合和数组都可以使用fori遍历
解决有序的单列集合。
存取有序
有索引
可重复
在Collection的基础上增加了有关下标的方法。
解决以数组为数据结构的集合。
默认构造函数创建一个空对象数组
第一次添加最低开辟空间为10个容量
超过容量了才会扩容,增加容量是(原来容量+原来容量除2)
扩容过后还不够,直接扩容到所需容量
数组的最大长度是int的最大值
可以添加任意个null
解决以数组为数据结构并且是线程安全的集合。
默认构造函数创建10个容量
超过了容量才会扩容,增加容量是(原来的两倍)
【要是设置了容量增长个数,就是(原来容量+增长个数)】
扩容过后还不够,直接扩容到所需容量
数组的最大长度是int的最大值
可以添加任意个null
解决以双向列表和双端队列数据结构的集合
集合属性维护前后两个节点
Node内部类维护前后两个Node节点和本类数据
每一次操作都是两端开始【双端队列】
可以添加任意个null
解决不重复元素的单列集合。
不重复
无索引
存取无序
在Collection的基础上没有方法增加。
解决以hash表为数据结构的集合
HashSet里面维护了一个HashMap集合
存放数据是将HashSet的数据存放到HashMap的key中,HashMap的value使用空值常量
可以为null
解决以hash表为数据结构还维护了一个双向链表。
LinkedHashSet全是调用HashSet的方法,维护了一个LinkedHashMap
可以为null
解决以红黑树为数据结构的集合
底层维护了一个TreeMap
解决双列数据的集合
所有的Key都和Set的值一样
唯一不同的是,Set使用的value是常量
Map中的Node元素遍历方法。
entrySet方法获取所有的k-v
keySet方法获取所有的k
values方法获取所有的v
解决以Hash表为数据结构的集合
扩容机制
默认构造不给数组赋值
第一次添加会扩容到16个容量
根据key计算数组的索引【计算下标】
情况一:hash处理之所在数组下标为空,直接存放到table数组
情况二:hash处理之所在数组下标不为空
情况一:找到根节点【重复不添加】
情况二:找到根节点,为树结构【树结构添加】
最后:先遍历链表
如果结尾为空直接存放,如果链表长度等于8【树化】
如果链表中数据【重复不添加】
最后:添加成功
【节点介入后】【LinkedHashMap扩展方法】
判断达到0.75的阈值进行扩容【扩容】
【插入节点后】【LinkedHashMap扩展方法】
中括号解析
【计算下标】(key的hash值异或key的hash无符号右移16位)再与计算数组最大下标
【重复不添加】(key的值相等或者key的equals相等)
【树化】
情况一:数组容量小于64先扩容
情况二:红黑树化
【树结构添加】
【扩容】
情况一:原来表的容量大于0
情况一:原来容量达到2的30次方(Integer最大值)
情况二:没达到2的30次方且容量达到16【两倍扩容】
情况二:阈值大于0(将阈值赋值给新的容量)
情况三:新的容量为16,新的阈值为0.75*16
如果阈值等于0
新容量和阈值都小于2的30次方,返回0.75阈值
否则返回Integer的最大值阈值。
遍历复制数据【第一个不为空才复制】
情况一:下一个为空,直接找到对应下标存放
情况二:红黑树遍历
情况三:链表遍历
数据结构
链表:Node元素是维护了(key的hash处理值,key,value,下一个Node节点)
红黑树:TreeNode元素维护了(父节点,左子节点,右子节点,上一页节点,红黑判断)间接继承了Node元素
解决以hash表为数据结构还维护了一个双向链表。
默认初始化是16个容量,最大初始化是2的30个容量
扩容机制和HashMap一样
解决以红黑树为数据结构的集合。
以key值作为比较
没给Comparator比较器,使用Comparable比较【类实现】
给了Comparator比较器,就不使用默认比较器【构造传入】
解决线程安全的hash表。
K和V都不能为空
value可以覆盖
默认构造函数初始容量是11
下标计算【hashcode与上一个Integer最大值,再对容量取模】.
【扩容】两倍+1的扩容机制。
解决加载properties文件的集合。
本身继承自HashTable,集合和HashTable如出一辙
可以使用该集合读取Properties配置文件
解决集合的通用处理方法。
解决数据类型的类型定义。【默认Object】
声明泛型
类:普通属性,普通方法
接口:普通方法,抽象方法
泛型方法:可以声明
静态方法:必须在方法中定义
定义泛型
确定属性:只有类上定义可以使用
确定返回值
确定参数
使用
类:类上的泛型创建对象时候确定
接口:继承接口或者实现接口时候确定
泛型方法:调用的时候确定
解决数据类型的类型定义的范围。
?:是通配符,表示数据类型可用范围
extends A:A类及其子类
super A:A类及其父类
解决多个任务同时进行。
并发:一个处理器交替处理多个线程
并行:同一时刻多个处理器处理各自线程
Thread启动线程是start0的本地方法
调用本地方法之后,将该方法放入可运行线程
实际线程的调用由底层JVM虚拟机调用
Thread方法
【Boolean终止线程】
setName:设置线程名
getName:返回线程名
setPriority:设置线程优先级
getPriority:获取线程优先级
sleep:休眠
interrupt:中断线程【中断休眠】
yield:让行
join:插入其他线程
setDaemon(true):设置为守护线程
NEW:刚创建
RUNNABLE:可运行【Ready就绪和Running运行】
BLOCKE:阻塞
WAITING:等待
TIMED_WAITING:超时等待
TERMINATED:已退出
解决多线程中数据只允许一个线程访问。
解决可运行的代码使用对象锁,保证同步。
格式:synchronized(对象){}
对象:互斥锁标记
解决方法使用锁,保证方法同步。
格式:方法修饰符位置使用synchronized
静态方法:对象锁为类对象
普通方法:对象锁为当前对象
解决同步机制的问题。
在多线程中线程获取对象来执行同步代码
对象加锁,一次只能有一个线程获取该对象
解决同步锁配合使用问题。
释放锁
当前同步代码块,同步方法执行完毕。
方法中break或return。
出现异常。
wait方法。
不释放锁
sleep:进入超时等待状态,不会释放锁
yield:让行,还是在运行状态
解决信息传输,网络上内存对内存传输,本机上内存对硬盘传输。【必须关闭流】
解决磁盘存放资源问题。
资源路径
构造方法找到资源路径
getParent:获取父路径
getName:获取当前名称
getAbsoluteFile:获取绝对路径
文件文件夹判断
exitsts:是否存在
isFile:是文件
isDirectory:是文件夹
listFile:获取列表
文件
createNewFile:创建文件【单级创建】
length:文件大小
delete:删除文件
文件夹
mkdir:创建一级目录
mkdirs:创建多级目录
delete:删除空目录
解决资源输入。
分类
字节输入流
字符输入流:本质是输入转换流的子类
使用
读取一个字节/字符
读取一个字节/字符数组【可截取】
估计文件字节/字符数量【可一次全部读取】
跳过字节/字符读取个数
返回读取有效长度,读完返回-1。
解决资源输出。【必须刷新】【追加和覆盖】
分类
字节输出流
字符输出流:本质是输出转换流的子类
使用
写一个字节
写一个字节数组【可截取】
解决批量处理数据提供方法。
字符输入缓冲流:readLine读取一行
字符输出缓冲流:newLine换行【和系统相关】
字节输入缓冲流:内置数组
字节输出缓冲流:内置数组
解决存放数据的同时将数据类型也一并保存。
序列化:ObjectOutputStream
输出的时候write类型
默认所有的属性都参与序列化,除了static和transient成员
要求类中的属性都要实现Serializable接口
反序列化:ObjectInputStream
读取顺序和写出一致
有对应的类引用,向下转型
输入的时候read类型
Serializable
参与序列化的类都要实现Serializable接口
该接口有传递性,父类有子类就有了
SerialVersionUID序列号,当类修改了可以根据序列号找到反序列化的类
解决最基础的输入输出。
标准输入流:System.in
键盘输入:Scanner
编译类型:InputStream
运行类型:BufferInputStream
标准输出流:System.out
显示器输出:
编译类型:PrintStream
运行类型:PrintStream
解决将字节流转成字符流,根据编解码方式转换。
输入转换流:InputStreamReader。解码字符集
输出转换流:OutputStreamWriter。编码字符集
解决输出时候自动刷新。
打印字节流:PrintStream
打印字符流:PrintWriter
解决properties配置文件的读取和操作,本身就是一个集合。
格式:键=值
方法
load:加载文件到properties集合
list:输出到指定设备
getProperties:获取值
setProperties:设置键值对
store:将键值对保存到配置文件【Unicode编码】
解决计算机和计算机之间的通信问题。
解决网络标识问题。
网络范围
局域网:计算机连接网络的同一个设备
城域网:以城市为范围
广域网:比城市范围更大【互联网】
解决计算机在网络中的标识。【ipconfig查看IP】
IPv4
格式:xx.xx.xx.xx
范围:xx取值0-255
意义:以网络号+主机号组成
分类【一半的一半】
A类:0+7+24
B类:10+14+16
C类:110+21+8
D类:1110+28【广播】
E类:11110+27【待用】
【127.0.0.1】
购买的服务器IP才是固定的
解决IP记忆问题。【根据域名映射成指定的IP】
解决计算机上的程序标识问题。【netstat -an|more】
取值范围:0-65535
已经占用:0-1024
常见端口:tomcat8080,mysql3306等
解决数据传输中的编解码问题。
用户数据
应用HTTP:加上APP首部
传输TCP/UDP:加上TCP首部
网络IP:加上IP首部
以太网驱动:加上首位帧
解决数据传输时建立传输通道。
需要连接和释放连接【三次握手,四次挥手】
可进行大量数据传输
解决无连接数据传输。
将数据,源,目的封装包传输
数据报大小限制64K
解决Ip地址相关问题。
getLocalHost:获取本机InetAddress对象
getByName:获取指定主机名/域名InetAddress对象
getHostName:获取对象的主机名
getHostAddress:获取对象的地址
解决TCP通信问题
需要两个Socket进行IO传输
主动发起通信的是客户端,服务端阻塞等待客户端发送请求
使用
客户端:Socket(IP地址,端口),发送请求
服务端:ServiceSocket(端口),监听端口等待连接【阻塞】
ServiceSocket.accept:获取Socket对象
输入流读取【阻塞】
输出流写出:socket.shutdownOutput();【结束标记】【flush】
解决数据报无连接数据传输。
接收端
DatagramSocket:接收数据报【监听端口】receive
DatagramPacket:参数字符数组
发送端
DatagramSocket:接收数据报【发送端口】send
DatagramPacket:UDP数据报,接收端IP和端口
解决根据路径的字符串创建对象的方法。
Class.newInstance:创建实例
获取类对象
Class.forName:编译阶段
Class.class:加载阶段
class.getClass:运行阶段
ClassLoader.loadClass:类加载器加载全类名
基本类型.class
包装类型.TYPE
使用类对象方法
getClassLoader:获取类加载器
获取方法对象
Class.getMethod(名称,参数列表)【仅公共】
Class.getDeclaredMethod(名称,参数列表)【仅类中声明】
使用方法对象
setAccessible:暴力调用
Method.invoke(对象)调用方法
获取属性对象
Class.getField(名称)【仅公共】
Class.getDeclaredField(名称)【仅类中声明】
使用属性对象
get(对象)
set(对象,值)
获取构造对象
getConstructor(参数)【仅公共】
getDeclaredConstructor(参数)【仅类中声明】
使用构造对象
newInstance
类,成员内部类,静态内部类,局部内部类,匿名内部类
枚举
接口
注解
数组
基本类型
void
静态:加载的类信息中只要有new就会被加载。
动态:不执行的时候不会创建对象,也不会报错
只需要一个MySQL驱动包。
解决关系型数据库的统一规范。【本质是数据交互关闭流】
解决数据库驱动的管理
Driver驱动类固定:com.mysql.cj.jdbc.Driver
原始管理驱动:DriverManager.registerDriver(new Driver());
JDK5之后的jdbc4会自动找到jar包下META-INF\services\java.sql.Driver去注册
解决客户端和数据的连接问题
获取连接:DriverManager.getConnection(url,username,password);
url:jdbc:mysql://IP:port/库名?【serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true&rewriteBatchedStatements=true】
user:账号
password:密码
解决向数据库发送静态SQL。
Connection.createStatement:获取声明对象
execute:执行CRUD返回boolean
executeQuery:执行查询返回resultSet
executeUpdate:执行增删改返回int
解决数据库获取结果集【List<Map>结构】
next:光标从第一行前面开始向下走,有数据返回true,没有数据返回false
get类型(int):根据列的第几列去取值
get类型(String):根据列的标签去取值
解决向数据库发送动态SQL。
SQL语句以?来占位
Connection.prepareStatement(SQL语句):获取预编译声明对象
set(index):给?设置
executeQuery:执行查询返回resultSet
executeUpdate:执行增删改返回int
解决主键自增长回显功能
Connection.prepareStatement(SQL语句,Statement.RETURN_GENERATED_KEYS):
PrepareStatement.getGeneratedKeys():将主键结果封装到resultSet中
解决插入的数据过多。
addBatch:不执行,追加values后面
executeBatch:批量执行
url上设置rewriteBatchedStatements=true
SQL语句不能使用;号
解决JDBC中的事务问题。
JDBC的事务是自动提交。
JDBC事务使用Try,Catch
JDBC以连接为单位
只需要Mysql驱动包和Druid的依赖。
解决创建连接关闭连接浪费时间的问题。
连接池统一规范。【Druid】
解决数据库连接的最优秀连接池。
DruidDataSourceFactory.createDataSource(prop配置文件):工厂创建连接池
DruidDataSource:连接池接口实现
设置连接
setDriverClassName:设置driver
setUrl:设置url
setUsername:设置user
setPassword:设置password
getConnection:获取连接
Connection.close:回收连接
【为同一个线程任何位置都是取到同一个连接,线程绑定数据源】
解决JDBC的封装工具
QuertRunner(DataSource):核心API可以绑定数据源
ResultSetHandler:结果集处理器【handle方法处理结果集】
SQL:书写用?代表占位符
解决提取文章中的复合表达式规则的数据。
步骤
模式编译:Pattern.compile("\d\d");
完整匹配:Pattern.matches(regex, CharSequence)
获取匹配器:compile.matcher(s);
开始匹配:matcher.find()【返回是否匹配到】
找到结果,将结果记录在matcher属性中
oldLast:记录下一个开始匹配的下标。
groups数组:记录【每一组】的下标
获取匹配结果:matcher.group(0)
group(int):从【第几组】下标截取字符串
转义字符:\
[]:可以接收的单个字符。
[^]:排除接收的单个字符。
-:连字符一定的范围。
.:可以接收任意一个非空格符号
\\d:可以接收单个数字【大写取反】
\\w:可以接收单个数字和字母【大写取反】
\\s:可以接收任何空白【大写取反】
【(?!):后面的字母不区分大小写】
|:选择前面一种或者后面一种,最大范围选择
*:任意次数
+:最少一次
?:最多一次
{n}:n次
{n,}:最少nci
{n,m}:n次到m次
【后面加?:非贪心捕获,最小数量匹配。】
^:定位开始字符
$:定位结束字符
\\b:匹配字符结尾有空格【大写取反】
捕获分组
(pattern):非命名捕获。从左往右1开始排号
(?<name> pattern):命名捕获。还可以使用组名获取分组
非捕获分组
(?: pattern):局部选择。
(?= pattern):处于结尾,前面的字符匹配就选择。
(?!pattern):处于结尾,前面的字符匹配不选择。
解决已经分组捕获的内容【后】进行引用。
\\分组号:内部反向引用,表达式内部使用
$分组号:外部反向引用。
$使用:matcher.replaceAll("$1"):使用反向引用代替匹配的字符。
解决页面内容书写。
解决HTML文件书写格式。
声明
html根标签
首部
meta
title
尾部
解决HTML文件最基本的组成
单标签
双标签【内容】
属性
基本属性
事件属性
解决使用HTML的最基本规则。
【注释】<!-- -->
大小写不敏感
标签不能交叉嵌套
标签必须闭合
属性必须有值且值要加引号
解决HTML编写问题【使用W3cSchool】
base参照地址:href当前标签地址。其他标签的href相对地址会根据该标签去访问。
html字符实体:&打头;结尾
font:字体标签
br:换行标签
h1-h6:标题标签
a:超链接。href写url连接,target响应目标页面显示。
ol或ul:ol是有序列表,ul是无序列表。li是列表项。
img:显示图片。src路径。
table:表格。tr行,td格,th标题格。colspan跨列,rowspan跨行。
ifarme:内嵌窗口。
div:独占一行。
span:片段。
p:段落。
解决表单提交数据。
form
action:服务器地址
method:提交方式
input
text:文本框
password:加密文本框
select:下拉框。option选项标签【selected="selected"代表选中】
redio:单选框【checked="checked"代表选中】
checkbox:多选框【checked="checked"代表选中】
textarea:多行文本框
reset:重新到默认选择
submit:提交按钮
button:按钮
file:文件上传
hidden:隐藏域
GET请求
地址栏:action+?+请求参数
长度有限制
POST请求
地址栏:只有action
没有长度限制
java路径
绝对路径:从盘符开始
相对路径:/服务器解析http:/ip:port/工程路径
web路径
绝对路径:从HTTP开始
相对路径:从当前所在目录开始
.标识当前目录
..上一级目录
文件名相当于./文件名
/浏览器解析:http:/ip:port/
特殊:sendRediect("/")会交给浏览器解析
解决网页页面美化问题。
注释/* */
选择器{属性:值;}
方式一:属性直接使用
html的style属性:style="key: value;"
方式二:头标中
<style type="text/css">中使用下面的代码
选择器{属性:值;}
方式三:头标中引入外部文件
<link rel="stylesheet" type="text/css" href="web路径"/>
外部文件书写:选择器{属性:值;}
标签名选择器:标签名{}
id选择器:#id值{}
class选择器:.class值{}
【多个选择器使用逗号隔开】
解决网页动态显示问题。
方式一:头或尾标签种使用script标签
<script type="text/javascripe">标签下写代码
方式二:头文件种进行外部引入
<script type="text/javascripe" src="web路径">
类型
number:数值
string:字符串
object:对象
boolean:布尔
function:函数
特殊值
undefind:未初始化
null:空值
NAN:不是数字
关系运算
==:比较内容
===:比较内容和类型
逻辑运算
&&:返回第一个错误的值或者返回最后一个正确的值
||:返回第一个正确的值或者返回最后一个错误的值
!:取反
【0,null,undefined,空串。都是false】
函数名称相同会被覆盖掉。
隐形参数arguments
定义
方式一:function定义
function 函数名(形参列表){}
方式二:函数赋值给变量
var 函数名 = funcation(形参列表){}
函数例子
alert:提示框
typeof:返回数据类型
定义
方式一:花括号定义
var 对象名 = {};
方式二:对象赋值给变量
var 对象名 = new Object{};
[]:空数组
[1,53,'asd']:定义数组同时初始化
静态注册
使用事件种类的属性名
事件属性名="事件没有;结束"
事件属性名="函数调用"
动态注册
获取标签的dom对象
dom对象.事件名=function(){}
页面加载事件
固定:window.οnlοad=函数
onload:页面加载完成
onclick:单机
oblur:失去焦点
onchange:内容发送变化
obsubmit:表单提交
获取对象
根据id获取:document.getElementById(id)
根据name获取:document.getElementByName(Name)
根据标签类型获取:document.getElementByTagName(TagName)
标准使用
new RegExp(pattern):获取模板对象
regExp.test:判断是否包含
简单使用
var regExp= /pattern/:获取模板对象
regExp.test:判断是否包含
只需要一个JQuery的文件。
解决$代表JQuery对象
传入函数:页面加载之后执行。
HTML字符串:创建元素节点对象。
选择器字符串:查找相关节点对象。
DOM对象:将DOM对象包装成JQuery对象。
DOM对象
表现形式:alert出来是[object HTMLButtonElement]
document获取的对象都是DOM对象
JQuey对象
表现形式:alert出来是[object object]
JQuery函数返回的对象都是JQuery对象
本质上是一个对DOM对象数组
文档声明
元素
注释:<!-- -->
CDATA:<![CDATA[不解析内容]]>
只需要一个依赖包
SAXReader对象
read方法读取xml文件:获取document对象
bin:可执行命令
conf:配置文件
lib:依赖包
logs:日志存放
temp:临时数据
webapps:部署工程
work:存放运行时jsp翻译的servlet源码,session钝化(序列化)
启动
方式一:startup.bat点击
方式二:DOS窗口运行startup.bat
关闭
方式一:shutdown.bat点击
方式二:关闭黑窗口
【使用了JAVA_HOME的环境变量】
端口号:conf/server.xml下边
方式一
把web工程放在webapps目录下即可
方式二
conf/Catalina/loadhost下放一个xml文件
xml文件书写:<Context path="/工程路径" docBase="工程绝对路径"/>
只要servlet-api依赖。
实现servlet接口
web.xml配置映射信息
构造方法:第一次访问时候创建对象
init方法:对象创建完成之后初始化
service方法:每一次访问都会调用
destroy方法:容器关闭的时候调用
获取初始化参数<init-param>
获取ServletContext对象
获取程序别名<servlet-name>
【维护父类变量:重写了初始化方法,其他方法getServletConfig是从父类获取】
获取工程信息
获取工程<context-param>
域对象保存数据
请求行
请求方式
请求路径
协议版本号
请求头:K-V
请求空行【get请求没有】
请求体【get请求没有】
POST请求目前只有form表单能发送
响应行
协议版本号
状态码
状态码描述
响应头:K-V
响应空行
响应体
响应码
200:成功
302:重定向
404:请求地址错误
500:服务器内部错误
HTTP协议中数据类型。
解决请求到服务器之后,自动将请求数据封装到HttpServletRequest,传递给service方法使用
getRequestURL:获取请求路径
getMethod:获取请求方式
getRequestHeader:获取请求头
getParameter:获取value为单值的参数
getParameterValues:获取value为多值的参数
setAttribute:向request域中存放数据
getAttribute:从request域中获取数据
请求POST中文乱码
setCharacterEncoding("UTF-8"):设置请求体的字符集
在获取请求参数之前调用
请求转发
getRequestDispatcher("/转发路径").forward(req,resp);
解决请求到服务器之后,自动创建一个新的HttpServletResponse,传递给service方法使用
getOutputStream:获取响应字节流
getWriter:获取相应字符流
响应中文乱码
getCharacterEncoding:默认是ISO-8859-1,欧洲编码
setCharacterEncoding("UTF-8"):设置服务器字符集UTF-8
浏览器默认是GBK
setHeader("Content-type","text/html;charset=UTF-8"):设置相应解析编码
【综合上面:setContentType("text/html;charset=UTF-8")】
获取相应流之前设置才有效
请求重定向
setStatus(302):设置相应编码
setHeader("Location","请求路径"):设置重定向地址
【综合上面:setRedirect("请求路径")】
只需要一个jsp-api依赖。
JSP本质是servlet的另一种书写形式。
<%@ page contentType="text/html;charset=utf-8" languge="java" %>
HTML标签
一共有三种指令
page指令。jsp配置信息。
include指令。动态包含。也可以写成<jsp:include>。
taglib指令。引入JSTL标签库。
声明脚本:<%! 定义类的代码 %>【serlvet类中】
表达式脚本:<%= jsp页面输出数据 %>【_jspService方法的out.print代码】所以不能以分号结尾
代码脚本:<% java语句 %>【_jspService方法中】
html注释:<!-- 表达式脚本中 -->
java注释:<% 传递到servlet源码中 %>
jsp注释:<%-- 注释掉所有的内容 --%>
request
response
pageContext
session
application
config
out
page
exception【需要开启】
四大域对象
pageContext
request
session
application
他们各自输出到自己的缓冲区
然后out将自己缓冲区的内容追加到response缓冲区
最后由response缓冲区将数据相应给浏览器
write:直接将数据返回给浏览器
print:在write的基础上对各种数据都进行了String类型处理
格式:<%@ include file="/"%>
静态包含是将另外一个jsp的页面内容放在引入标签位置,生成一个servlet。
格式:<jsp:include page=""/>
动态包含是将另外一个jsp对应的servlet的方法调用。
格式:<jsp:forward page="路径"/>
【JSP不能直接相应客户端】
<jsp:include > 动态包含
<jsp:forward > 请求转发
<jsp:param > 设置请求参数
<jsp:useBean > 创建一个对象
<jsp:setProperty > 给指定的对象属性赋值
<jsp:getProperty > 取出指定对象的属性值
三大对象创建销毁监听
ServletContextListener
HttpSessionListener
ServletRequestListener
三大对象域内容增删改
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
对象绑定
HttpSessionBindingListener:实现该接口的类,存到session或者取出都会触发绑定和解绑方法。
HttpSessionActivationListener:实现该接口,钝化(序列化),活化(反序列化)都是由容器执行,会调用该接口的方法。
解决JSP从四大域中获取数据。Expression Language空值会输出空白而不是null。
格式:${key}
输出格式
对象和map:{}
数组:[]
其他属性:键值对
域对象中获取数据setAttribute("p",person)
输出基本属性:p.name
输出数组属性:p.arr
输出数组元素:p.arr[下标]
输出map集合属性:p.map
输出map集合元素中的值:p.map.key【key值比较特殊可以[]括起来】
关系运算
逻辑运算
算术运算
三元运算符
empty判断是否为空
null值
空串
集合长度为0
对象数组长度为0
pageContext:page上下文
pageScope:page域
requestScope:request域
sessionScope:session域
applicationScope:application域
param:获取单值参数
paramValues:获取多值参数
header:获取单值请求头
headerValues:获取多值请求头
cookie:获取Cookie信息
initParam:获取web.xml配置的context-param
只需要导入taglib-standard-(impl和spec)两个依赖。
解决JSP文件中的代码脚本编写。
核心库:包名core。前缀c。
格式化:包名fmt。前缀fmt。
函数:包名functions。前缀fn。
数据库:三层架构,只需要Dao层访问数据库。
xml:现在用json来和浏览器交互数据。
引入<%@ taglib prefix="前缀" url="Oracle Java Technologies | Oracle包名"%>
forEach:遍历
set:向域中设置变量
if:选择执行
choose:多选一。配合when和otherwise标签。
只需要commons-(fileupload和io)两个依赖
发送form表单,method=post请求,encType=multipart/form-data
表单项type=file,name表单项名
ServletFileUpload类解析上传数据
isMultipartContent:判断请求是多段格式数据
parseRequest:解析请求【返回FileItem集合】
isFormField:判断是普通表单项
getFieldName:获取表单项name属性
getString:获取表单项的值
getName:获取上传的文件名
write:文件输出到磁盘
ServletContext.getResourceAsStream:获取资源流
ServletContext.getMimeType:获取下载文件的MIME类型
resp.setContentType(mimeType):设置响应类型
resp.setHeader("Content-Disposition","attachment;filename=文件名"):设置下载头
获取响应流
IOUtils.copy(输入流,输出流):复制流数据
URL编解码
解决中文转成URL格式:%xx%xx%xx
谷歌和IE
URLEncoder.encode("中文"):编码
URLDecoder.decode(String):解码
火狐【BASE64编码】
文件名格式:=?charset?B?xxxxx?=【xxxxx就是BASE64编码】
BASE64Encoder.encodeBuffer("中文".getBytes("UTF-8")):编码
BASE64Decoder.decodeBuffer(String):解码
解决浏览器数据保存。
服务器创建的Cookie对象,发送到浏览器就转成了cookie请求头
cookie大小不能超过4kb
new Cookie("key","value"):创建一个cookie对象【可以覆盖】
resp.addCookie(cookie):响应给客户端
req.getCookies:获取请求头中的cookie封装成cookie数组
【不支持中文等特殊字符,要使用BASE64编码】
setMaxAge方法
正数:存活秒数
负数:关闭浏览器就删除
0:立即删除
Cookie的path默认是当前工程路径
当发送的URL地址包含Cookie的path路径的时候,cookie才会有效
解决解决服务器保存浏览器和服务器之间需要的数据。
服务器创建Session对象
将SESSIONID存储到Cookie头中
req.getSession:第一次get是创建,第二次get就是根据cookie中的JSESSIONID获取对应的Session对象。
isNew:判断是不是刚创建的。
getId:获取SESSIONID值
setAttribute:向session存值
getAttribute:从session取值
setMaxInactiveInterval:设置超时时长
getMaxInactiveInterval:获取超时时长
正数:超时时长【可以刷新】
负数:永不超时
invalidate:设置会话无效
解决请求安全性。
类实现Filter接口
在web.xml文件中配置映射路径
构造方法:web启动的时候Filter就创建
init初始化:Filter对象创建之后自动初始化
doFilter过滤方法:每次拦截到请求就会执行
destroy销毁方法:关闭服务器
获取filter-name
获取init-param
获取ServletContext对象
异常统一处理
本来是用过滤器去转发的。
可以在web.xml配置中配置error-pagr设置异常统一转发页面
正常执行
第一个过滤器拦截到FilterChain.doFilter找到第二个过滤器
第二个过滤器拦截到FilterChain.doFilter请求资源
响应第二个过滤器FilterChain.doFilter之后的代码
响应第一个过滤器FilterChain.doFilter之后的代码
第二个过滤器拦截
第一个过滤器拦截到FilterChain.doFilter找到第二个过滤器
第二个过滤器拦截到FilterChain.doFilter拦截
响应第二个过滤器FilterChain.doFilter之后的代码【不执行】
响应第一个过滤器FilterChain.doFilter之后的代码
拦截器链是根据web.xml配置的顺序来执行。
精准匹配
目录匹配:*代表目录
后缀名匹配:*.html
解决当前线程存储数据。
ThreadLocal对象存储在ThreadLocalMap中
每一个当前线程都绑定了一个ThreadLocalMap
ThreadLocal对象简单理解为以当前线程为key,设置的值为value
只需要gson依赖。
解决服务器和浏览器数据交换的格式
JS中定义JSON对象:var json = {"key"="value","key"="value"};
Java中定义JSON
stringify:json对象转成json字符串
parse:json字符串转成json对象
核心api是Gson
toJson:将javaBean转成json字符串
对象
List集合
Map集合。
fromJson(json字符串,Class):json字符串转成javaBean对象
fromJson(json字符串,new TypeToken<>(具体类型).getType):json字符串转成list或map集合
解决浏览器的js和服务器的数据异步交互。
核心api是XMLHttpRequest。
var ajax = new XMLHttpRequest();:获取核心对象
open(method,url,async)true表示异步:设置请求参数
onreadystatechange:readyState发送改变自动调用该事件
send(string):发送请求数据
获取响应API:responseText和responseXML。
status:200和404取值
readyState
0:表示请求未初始化
1:表示请求已连接
2:请求已接收
3:请求已处理
4:请求已完成,准备相应
未封装:$.ajax(js对象);
get请求封装:$.get(对应的js对象);
post请求封装:$.post(对应的js对象);
getJson请求封装:$.getJson(对应的js对象);
$.ajax()
url:地址
type:mthod请求方式
data:请求参数【js对象】
success:回调函数【一定要加上一个参数】
dataType:响应类型【text,xml,json】
$.get()和$.post()
url:data:callback:type。
按照顺序直接书写value对应的js对象
$.getJson()
url:data:callback。
按照顺序直接书写value对应的js对象
解决将表单数据转换成url格式的数据。
解决不同语言的显示。
Locale:表示不同时区,位置,语言
properties文件:baseName+_locale+.properties
ResourceBundle
getBundle:根据baseName和Locale读取配置文件
getString:根据key获取里面的值
格式化标签库
fmt:setLocale:设置Locale
fmt:setBundle:设置baseName
fmt:message:从文件中获取值key=?
内部书写
格式:<!DOCTYPE 根元素[约束]>根元素
元素约束
<!ELEMENT 元素名称 类别>:类别【ANY,EMPTY】
<!ELEMENT 元素名称 (子元素内容)>:元素内容【子元素,字符串#PCDATA】
出现次数:+,?,*,|。
属性约束
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
属性类型和默认值查找w3cschool文档
实体约束
内部实体定义:<!ENTITY 实体名称 "实体的值">
使用:【&实体名称;】
外部实体定义:<!ENTITY 实体名称 SYSTEM "URI/URL">
外部引入
将除了根元素的约束,保存到dtd文件中
<!DOCTYPE 根元素 SYSTEM "DTD文件路径">:引入自定义DTD
<!DOCTYPE 根元素 PUBLIC "PUBLIC ID" "DTD文件路径">:引入别人定义的DTD
更细致化的约束:值的范围,正则表达式,出现次数,顺序。
支持命名空间,在不同的命名空间下面,可以有重复元素名。
schema约束文件必须和xml文件分离。
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3school.com.cn" xmlns="http://www.w3school.com.cn" elementFormDefault="qualified">
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xs:是前缀
schema用到的元素和类型来自此命名空间,被约束
targetNamespace="http://www.w3school.com.cn"
schema定义的元素来自此命名空间,当前文件命名空间
xmlns="http://www.w3school.com.cn"
默认的命名空间
elementFormDefault="qualified"
任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定,被约束文件必须满足该约束。
元素:<xs:element name="元素名称" type="元素类型" default="默认值">
属性:<xs:attribute name="属性名称" type="属性类型" default="默认值"/>
<?xml version="1.0"?> <note xmlns="http://www.w3school.com.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3school.com.cn note.xsd">
xmlns="http://www.w3school.com.cn"
默认命名空间声明,被约束的命名空间。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
XML实例命名空间,从网络中获取。【默认】
xsi:schemaLocation="http://www.w3school.com.cn note.xsd"
第一个值是所需要使用的命名空间,被约束的名称空间
第二个值是给名称空间使用的XMLschema的位置,被约束文件的文件名。
必须是函数式接口
解决只有一个抽象方法的接口
Consumer消费型接口【有参数,无返回】
Supplier供给型接口【无参数,有返回】
Function函数型接口【有参数,有返回】
Predicate断定型接口【判断true或者false】
有参数
无参数
返回值用return
一个参数小括号可以省略
参数类型可以省略
Lambda只有一条代码大括号可以省略
解决引用方法和函数式接口方法参数和返回值一致。
对象::实例方法名
类::静态方法名
类::实例方法名
示例:(s1,s2)->s1.compareTo(s2)。等同于String::compareTo。
类::new
String[]::new
解决集合和数组的数据计算,不会存储元素,不会改变对象,只有在就终止时候才会执行。
Collection.stream:顺序流
Collection.parallelStream:并行流
Arrays.stream(str);
Stream.of();
Stream.iterate(0,t->t + 2):无限迭代流
Stream.generate(Math::random):无限生成流
筛选【传入条件】
filter:过滤元素
distinct:去重,通过hashCode和equals去重元素
limit:截断流,截取前段数据
skip:跳过元素,去除前段数据
映射【传入函数】
map:内部元素处理获得新元素
faltMap:内部流元素处理获得一个新的流
排序【传入比较器】
sorted:自然排序
sorted(比较器):比较器排序
匹配【传入Predicate函数】
allMatch:是否匹配所有元素
anyMatch:是否匹配到任意元素
noneMatch:是否匹配不到元素
获取
findFirst:返回第一个元素
findAny:返回任意一个元素
count:返回元素个数
max:返回元素最大值
min:返回元素最小值
forEach:遍历内部元素
归约
reduce(T,BinaryOperator):以T开始,执行三个T的function
reduce(BinaryOperator):执行三个T的function
收集
collect(Collector):收集到Collector接口的实现类
Collector工具类Collectors
解决空指针问题,空对象返回一个null。
创建对象
of(T):T必须非空
empty():空实例
ofNullable(T):T可以为null
判断内部对象
isPresent():判断是否包含对象
ifPresent(consumer):如果有值就传参并执行consumer函数
获取对象
get():有对象返回对象,没对象报错
orElse(Object other):有对象返回对象,没对象返回other
orElseGet(Supplier):有对象返回对象,没对象返回Supplier提供的对象
orElseThrow(Supplier):有对象返回对象,没对象返回Supplier提供的异常
不改变源码的情况下给实现方法进行增强。
将(目标对象)和(增强代码的对象)交给(目标对象的另一个实现类),再调用代理类将两个对象传给代理类。
解决有接口的实现类的不修改源码增强。
public class MyInvocationHandler implements InvocationHandler { Object o; public MyInvocationHandler(Object o) { this.o = o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(o,args); } }
Proxy.newProxyInstance(Target.class.getClassLoader(), Target.class.getInterfaces(), new MyInvocationHandler(new T()));
只需要cglib依赖。
解决没有接口的实现类的不修改源码增强。
public class MyInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o,objects); } }
MyInterceptor myInterceptor = new MyInterceptor(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Target.class); enhancer.setCallback(myInterceptor); Target target = (Target) enhancer.create();
使用框架三步走:依赖,配置,使用。
只需要Beans,Core,Context,Expression,commons-logging五个依赖。
解决对象的创建交给第三方容器。
解决IOC的实现原理。
原生new代码到处写
使用工厂模式new代码提取到一起
IOC是使用xml,反射,工厂模式【将所有配置的类存储到map集合】
解决IOC配置的基本标签。
<bean id="" class=""/>:配置id和全限定类名
<bean name="">:配置别名获取bean
<bean scope=”>:配置单例多例
<bean lazy-init="">:配置懒加载【applicationContext才有效】
<beans profile="环境名称">:指定环境
虚拟机:-Dspring.profiles.active=环境名称
设置环境变量:System.setProperty("spring.profiles.active","环境名称")
<import resource="">:引入外部资源
<alias>:起别名
构造方式实例化Bean。
工厂方式实例化Bean。
<bean factory-bean="Bean的id" factory-method="工厂中的方法">:【普通工厂实例化Bean】
<bean class="全限定类名" factory-method="工厂中的方法">:【静态工厂实例化Bean】
解决Bean在实例化之后的初始化的一个环节。
初始化方法:Bean实例化之后的初始化方法
销毁方法:Bean销毁之前的销毁方法【显示关闭调用销毁方法】
接口
InitializingBean:Bean初始化接口
DisposableBean:Bean销毁接口
配置文件
<bean init-method="">:Bean初始化配置
<bean destroy-method="">:Bean销毁配置
注解
@PostConstruct:Bean初始化注解
@PreDestroy:Bean销毁注解
解决IOC容器获取的方式。
BeanFactory:最顶层接口【懒加载】
DefaultListableBeanFactory:默认工厂实现
XmlBeanDefinitionReader(DefaultListableBeanFactory);读取器
read.loadBeanDefinition("bean.xml");读取文件
new ClassPathXmlApplicationContext("bean.xml"):从类路径获取配置
new FileSystemXmlApplicationContext("本地配置"):从磁盘回去配置
new AnnotationConfigApplicationContext("配置类"):加载配置类
BeanFactory和ApplicationContext区别
叫法
BeanFactory叫bean工厂
ApplicationContext叫String容器
功能
BeanFactory更底层
ApplicationContext对监听,国际化等进行扩展
Bean创建时机
BeanFactory调用时加载
ApplicationContext容器创建时加载
关系
ApplicationContext继承Factory
还进行了扩展
解决从容器中获取Bena。
方式一:根据beanName获取【需要强转】
方式二:根据beanType获取【类型唯一】
方式三:根据beanName和beanType获取
实现该接口
调用get获取该实现类的时候,调用的是该类的getObject方法
p名称空间使用,可以在bean上p:name对name属性注入。
null子标签可以代表属性的空值
<>对属性中的特殊符号转义
<![CDATA[]]>对内容中的特殊符号转义
<context:compont-scan base-package="包名"/>【@ComponentScan:扫描注解】
<context:property-placeholder location="classpath:jdbc.properties"/>【@PropertySource:加载properties】
${jdbc.url}使用spring的EL表达式【@Value:使用基本数据】
<aop:aspectj-autoproxy/>【@EnableAspectJAutoProxy:使用aop注解】
<tx:annotation-driven transaction-manager="transactionManager"/>【@EnableTransactionManagement:开启事务注解支持】
handlerMappings:解析器存储,在/META-INF/spring.handlers文件中
命名空间都包含在/META-INF/spring.schemas
根据不同的namespaceHandler去解析各自的配置信息。
对应框架的BeanDefinitionParser的paeser解析
要么注册BeanDefinition
要么BeanPostProcessor加入Bean
确定命名空间,schema虚拟路径,标签名称
编写约束文件
/META-INF/约束映射文件spring.schemas和处理器映射文件spring.handlers
NamespaceHandler处理器,并在init方法注册BeanDefinitionParser
BeanDefinitionParser解析器,并在parse注册BeanPostProcessor
编写BeanPostProcessor
引入约束文件【引入约束的命名空间和命名空间的地址文件。】
编写自定义标签
解决IOC容器中的Bean之间的关系,以及基本属性注入。
set注入Bean:<property name="属性" ref="Bean的id"/>
set注入值:<property name="属性" value="值"/>
construct注入Bean:<construct-arg name="形参" ref="Bean的id"/>
construct注入Bean:<construct-arg name="形参" value="值"/>
1. list:\\<value>aaa\</value>\</list> <list> <value>aaa</value> <ref bean="id值"/> </list> 2. map <map> <entry key="k1" value-ref="id值"/> </map> 3. properties <props> <prop key="k1">string</prop> </props>
配置文件
<bean autowire="byType">:根据set注入的名称
<bean autowire="byName">:根据set注入的参数类型
<bean autowire="byName">:根据构造注入
解决Bean实例化的整个过程
Spring容器初始化
【读取配置文件】
执行一系列的BeanFactoryPostProcessor实现类,【处理注解配置】【Bean工厂后置处理器】
【将配置文件封装成BeanDefinitionMap集合】
Spring再遍历BeanDefinitionMap集合使用反射创建Bean实例对象
调用构造方法
属性注入【DI】
Aware接口
postProcessBeforeInitalization【Bean后置处理器Before方法】
InitializingBean初始化接口
init-method初始化方法
postProcessAfterInitalization【Bean后置处理器After方法】
创建号的Bean对象存储到singletonObjects的Map集合中
getBean方法就是从singletonObjects的Map集合中获取对象
解决动态注册和修改BeanDefinition的扩展点。
使用
实现BeanFactoryPostProcessor接口
把实现类交给Spring容器【Spring自动调用该接口方法】
修改BeanDefinition
getBeanDefinition:获取BeanDefinition
BeanDefinition的方法直接修改【修改就生效】
注册BeanDefinition
创建RootBeanDefinition
ConfigurableListableBeanFactory向下转型DefaultListableBeanFactory并调用registerBeanDefinition
注册BeanDefinition。
专门注册BeanDefinition接口
BeanDefinitionRegistryPostProcessor接口继承BeanFactoryPostProcessor
postProcessBeanDefinitionRegistry方法专门注册BeanDefinition
实例化之后和初始化之后的两个扩展点。
解决动态修改Bean。
使用
实现BeanPostProcessor接口
把实现类交给Spring容器【Spring自动调用该接口方法】
postProcessBeforeInitalization:紧接着实例化执行
postProcessAfterInitalization:在init初始化之后执行
解决Bean实例化之后,到最后存储到SingletonObjects中。
实例化阶段
单例判断
延迟判断
FactoryBean判断
【实例化】
初始化阶段
属性填充,依赖注入
普通属性直接注入
单向对象注入,先创建被注入对象Bean实例
双向对象注入,循环依赖
执行Aware【根据接口注入对象】
执行BeanPostProcessor的Before
执行InitializingBean初始化
执行自定义初始化
执行BeanPostProcessor的After
解决属性注入先实例化所需bean,现在用引用代替。Spring使用三级缓存解决。
singletonObjects:单例池【对象没引用其他Bean】
earlySingletonObjects:早期单例池【对象引用其他Bean,且被引用】
ObjectFactory:对象工厂【对象引用其他Bean,但是没被引用】
执行顺序
实例化Bean放到三级缓存。
查找所需依赖,三个缓存都没有,去BeanDefinition实例化。
查找所需依赖,三级缓存有,将三级缓存的bean移动到二级缓存,完成三级缓存中满足属性注入的Bean加入到单例池。
查找所需依赖,一级二级缓存有就直接加入到单例池。
解决Bean对象使用相关的API,由Spring容器自动注入。
ServletContextAware:回调方法注入ServletContext【web环境才生效】
BeanFactoryAware:回调方法注入BeanFactory
BeanNameAware:回调方法注入BeanName
ApplicationContextAware:回调方法注入ApplicationContext
解决有关注解配置的使用。
2.5时代
<context:compont-scan base-package="包名"/>【扫描注解配置】
<context:property-placeholder location=""/>【加载properties配置】
3.0时代
@ComponentScan:扫描注解
@PropertySource:加载properties
@Configuration:代表application.xml配置文件【具有@Component作用】
@Import:引入其他配置类
@Primary:放在@Component或@Bean上,@Autowire获取Bean优先级更高
@Profile:放在@Component或@Bean上,表示指定环境下生效
【@Profile指定环境,第一虚拟机参数,第二环境变量System】
@Component:标识类,配置Bean
@Repository
@Service
@Controller
@Scope:标识bean类,作用范围
@Lazy:标识bean类,懒加载
@PostConstruct:标识bean类的方法,初始化方法
@PreDestroy:标识bean类的方法,销毁方法
@Bean:标识bean类的方法,自定义Bean【默认方法名称】【@Autowire可以省略】
解决属性注入,有set走set,没有就暴力反射。
@Value:注入普通数据
@Autowire:根据byType自动装配
@Qualifier:配合@Autowire再根据byName自动装配
@Resource:根据byType或byName自动装配
只需要aop和aspectjweaver依赖。【aop是一个思想,aspectjweaver是实现】
解决对使用动态代理某一个Bean进行增强。
本质就是在Spring容器,Bean后置处理器使用的动态代理。
Target目标对象
Proxy代理对象
Joinpoint连接点
Pointcut切入点
Advice通知
Aspect切面
Weaving织入
增强类书写
哪个包类方法需要增强
对目标方法那些通知进行增强
语法
execution([访问修饰符][返回类型][全限定类名][方法名称]([参数列表])) 1.权限修饰符:【可以省略】 2.返回类型:*代表任意字符Str* 3.全限定类名:*.代表任意字符,*..代表所有的包 4.方法名称:*代表任意字符, 5.参数列表:*代表任意类型,..代表任意类型任意个数 通配符
前置通知:@Before:前置通知
返回通知:@AfterReturning:返回通知【Returning属性:获取返回值】
异常通知:@AfterThrowing:异常通知【Throwing属性:获取异常信息】【针对目标】
最终通知:@After:最终通知
环绕通知:@Around:环绕【ProceedingJoinPoint:调用被代理方法】
环绕通知有限执行。
解决指定通知类的方法作为通知。
配置目标类Bean
配置通知类Bean
aop切面配置
pointcut切入点表达式
aspect代理类的通知方法,切入点绑定
解决实现了advice接口的类作为通知类。
配置目标类Bean
配置通知类Bean
实现了advice接口的通知类绑定一个advice配置
aop切面配置
pointcut切入点表达式
advice的配置,切入点绑定
开启注解支持:aop:aspectj-autoproxy配置或@EnableAspectJAutoProxy
配置目标类Bean
配置通知类Bean
@Aspect:切面配置
@PointCut:切入点
通知注解
@Order【值越小越先执行】
xml方式
<tx:advice>配置advice就行
目标方法配置属性
注解方式
@TransactionManager就不用配置advice和切面
加上<tx:annotation-driven transaction-manager="transactionManager"/>【自带AOP支持】
纯注解
@TransactionManager就不用配置advice和切面
@EnableTransactionManagement:开启事务支持【自带AOP支持】
PlatformTransactionManager接口:事务管理器
TransactionDefinition:事务设置
TransactionStatus:事务状态【提交回滚】
解决jdbc简单封装实现。
将JdbcTemplate中放入dataSource就行了。
只需要spring-test依赖。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:spring.xml")
复合注解@SpringJUnitConfig(locations="classpath:spring.xml")
Servlet3.1的核心api是Reactor,异步非阻塞。
解决其他框架整合。
不需要其他命名空间:Mybatis
需要其他命名空间:Dubbo
需要mybati-spring整合包,spring-jdbc和tx依赖。
注入Bean
SqlSessionFactory
MapperScannerConfig
书写Mapper
书写Mapper.xml
一共四个核心类
SqlSessionFactoryBean:提供SqlSessionFactory
MapperScannerConfigurer:扫描指定mapper注册BeanDefinition
MapperFactoryBean:获得指定mapper是调用getObject方法
ClassPathMapperScanner:definition.setAutowireMode【向MapperFactory自动注入SqlSessionFactory】
注册SsqlSessionFactory的bean对象
@MapperScan:扫描Mapper接口
原生整合
web的三大组件
SerlvetContextLisener监听器执行容器的创建
context-param配置上要加载的spring配置文件
WebApplicationContextUtils.getWebApplicationContext
spring-web依赖整合
监听器由整合包提供
工具类由整合包提供
只需要spring-webmvc依赖,javax-servlet-api:3.1.0【provided】不参与打包。
解决三个事情,servlet公共部分抽取,setvlet根据业务分Controller,servlet接入spring容器。
web配置文件
前端控制器ServletDispatcher
乱码过滤器CharacterEncodingFilter
请求方式过滤器HiddenHttpMethodFilter
mvc配置文件
mvc注解驱动【添加】
视图控制器
默认servlet
拦截器interceptor
上传解析器multipartResolver
异常处理器解析器SimpleMappingExceptionResolver
视图解析器viewResolver
MVC:模型,视图,控制器。
前端控制器获取请求
处理器映射器解析地址【处理器映射器】
返回处理器执行链
处理器适配器找到对应的处理器【处理器适配器】
处理器执行【处理器】
处理器返回结果数据
处理器适配器返回结果数据
视图解析器解析视图【视图解析器】
视图解析器返回视图对象
前端控制器响应
request.getParam获取单个参数
request.getParams获取多个参数
原生方法
Aware获取原生API获取请求参数
直接封装
保证名称一致,字符串获取多值时的格式:a,b,c
保证名称一致,数组获取多值的格式:[a,b,c]
对象接收参数
保证属性名称和参数一致。
获取请求信息相关注解
@RequestParam注解,封装请求参数【别名,集合不创建对象接收参数】
@RequestHeader注解,封装请求头
@CookieValue注解,封装cookie信息
三个注解都有这三个属性 1. name:映射名称 2. required:必须赋值【默认】 3. defaultValue:默认值
处理要求:处理乱码需要在获取参数之前设置请求编码。
get乱码:属于tomcat乱码,server.xml配置文件设置urlEncoding编码解决。
post乱码:在前端控制器之前执行编码。
过滤器解决CharacterEncodingFilter处理器
初始化参数:设置请求编码encoding
设置【响应】编码:设置forceResponseEncoding为true就可以了
原生ServletAPI向request域中存值。
ModelAndView【基本对象】
addObject:添加共享数据
setViewName:跳转页面
Model【Aware参数注入】
addAttribute:添加共享数据
Map【Aware参数注入】
put:添加共享数据
ModelMap【Aware参数注入】
addAttribute:向request中设置数据
【BindingAwareModelMap是根本实现类】
需要注解驱动的情况<mvc:annotation-driven />
视图控制器:<mvc:view-controller path="/" view-name="success"/>【请求地址和视图的映射,走视图解析器】
默认的servlet:<mvc:default-servlet-handler/>【处理静态资源】
java对象转成json:HttpMessageConvertor
HttpMessageConverter
@RequestBody:请求体
@ResponseBody:响应体【返回值转换成响应体】
RequestEntiry:请求报文对象
ResponseEntiry:响应报文对象
只需要jackson-(databind,core,annotations)依赖。
<mvc:annotation-driven />
@ResponseBody
下载:使用ResponseEntiry
bytes = 文件读取的字节数组。 headers = new HttpHeaders().add("Context-Disposition","attachment;filename=1.jpg") statusCode = HttpStatus.OK。 return new ResponseEntiry(bytes,headers,statusCode)
上传:【multipartResolver自动注入到Spring容器中】
只需要commons-(io和fileupload)两个依赖。
发送form表单,method=post请求,encType=multipart/form-data
表单项type=file,name表单项名
配置文件上传解析器:<bean id="multipartResolver" class="org.spingframework.multipart.commons.CommonsMultipartResolver"/>
MultipartFile【参数封装】
MultipartFile.transferTo:转存方法。
dispatcherServlet默认配置
<load-on-startup>1 springMVC的配置文件【默认】 WEB-INF下的【名称】<servlet-name>-servlet.xml
dispatcherServlet扩展配置
<init-param> param-name:contextConfigLocation param-value:classpath:springMVC.xml <load-on-startup>1
前端控制器处理/路径:表示的路径是除了JSP之外的处理,/*是所有处理。
使用在类上
给Controller处理器方法加上前缀。
使用在方法上
@RequestMapping("/hello") public String hello(){ System.out.println("hello请求进入"); return "hello"; }
value(path):映射请求地址
可以是数组多个请求映射
method:映射请求方式
可以是数组多个请求方式
params:映射请求参数
param:必须携带该参数
!param:必须不携带该参数
param=value:该参数一定定于该值
param!=value:该参数不等于该值
headers:映射请求头
header:必须携带该参数
!header:必须不携带该参数
header=value:该参数一定定于该值
header!=value:该参数不等于该值
@RequestMapping派生注解
@GetMapping
@PosyMapping
RequestMapping的映射路径。
?任意一个字符
*任意0-多个字符
**任意0-多层级目录
路径传参
/{id}:映射接收路径
@PathVariable("id")取出参数
页面请求:<input type="hidden" name="_method" value="put"/>
配置隐藏请求方式过滤器:HiddenHttpMethodFilter
【必须配置在乱码之后,因为此处获取了_method请求参数】
拦截器实现类
HandlerInterceptor接口的实现类
preHandler:处理之前拦截
postHandler:处理之后加强
afterComplation:视图渲染之后方法
配置拦截器
<mvc:interceptors>配置拦截器
<bean class=""/>:对所有请求拦截【通过类路径创建Bean】
<ref bean=""/>:对所有请求拦截【使用IOC中的对象】
<mvc:interceptor>:配置指定路径
<bean class=""/>:对指定请求拦截【通过类路径创建Bean】
<ref bean=""/>:对指定请求拦截【使用IOC中的对象】
<mvc:mapping path=""/>:包含指定路径
<mvc:exclude-mapping path=""/>:排除指定路径
正常执行
按配置顺序一顺执行完毕两个preHandler
处理器处理请求
按配置顺序反向执行两个postHandler
按配置顺序反向执行两个afterComplation
第二个拦截器拦截
按配置顺序一顺执行完毕两个preHandler
处理器和postHandler都【不执行】
执行第一个afterComplation
DefaultHandlerExceptionResolver【mvc默认异常处理实现】
SimpleMappingExceptionResolver【自定义异常处理】
SimpleMappingExceptionResolver配置bean
属性
exceptionMappings:K是异常,V是新的视图
exceptionAttribute:向请求域中存储错误信息
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="异常类">视图【过视图解析器】</prop> </props> </property> <property name="exceptionAttribute" value="ex"/>【异常信息key为ex存放到request域中】 </bean>
@ControllererAdvice:标志类是异常处理组件
@ExceptionHandler(异常类):处理哪一个异常
方法上放Exception和Model
@ControllerAdvice public class MyExceptionController{ @ExceptionHandler(异常类) public String testException(Exception ex,Model model){ model.setAttribute("ex",ex); return "视图【过视图解析器】"; } }
使用在控制器类上:@Controller
使用在控制器类上:@RestController等同于给每个方法【额外加上@ResponseBody】
视图解析器:【JSTL:InternalResourceView】,ThymeleafView。
转发:InternalResourceView【forward:/testView】Servlet
重定向:RedirectView【Redirect:/testView】Servlet
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 视图前缀 --> <property name="prefix" value="/WEB-INF/templates/"/> <!-- 视图后缀 --> <property name="suffix" value=".html"/> </bean>
只需要thymeleaf-spring5依赖。
<!-- 配置Thymeleaf视图解析器 --> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"/><!--视图优先级--> <property name="characterEncoding" value="UTF-8"/><!--编码--> <property name="templateEngine"><!--模板--> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"><!--spring模板--> <property name="templateResolver"><!--模板解析器--> <!--spring资源模板解析器--> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <!-- 视图前缀 --> <property name="prefix" value="/WEB-INF/templates/"/> <!-- 视图后缀 --> <property name="suffix" value=".html"/> <property name="templateMode" value="HTML5"/><!--模板模式--> <property name="characterEncoding" value="UTF-8"/><!--编码--> </bean> </property> </bean> </property> </bean>
<html lang="en" xmlns:th="http://www.thymeleaf.org">:引入约束
<a th:href="@{/hello}">访问hello页面</a>:相对请求路径
servlet(username='admin',password=123456):设置参数
可以使用th的EL表达式。
<welcom-file-list> <welcome-file>index.html\<welcome-file> </welcom-file-list>
400,请求参数不匹配。
404,请求路径不匹配。
405,请求方式不匹配。
注解配置本质
Servlet3.0会自动查找ServletContainerInitializer接口的实现类
Spring实现ServletContainerInitializer接口的类SpringServletContainerInitializer
SpringServletContainerInitializer查找WebApplicationInitializer接口的实现类
Spring3.2提供WebApplicationInitializer的实现抽象类AbstractAnnotationConfigDispatcherServletInitializer
web配置类使用
实现AbstractAnnotationConfigDispatcherServletInitializer
getRootConfigClasses:设置Spring配置
getServletConfigClasses:设置SpringMVC配置
getServletMappings:配置前端控制器路径
getServletFilters:设置过滤器
mvc配置类使用
实现WebMvcConfigurer
扫描组件:@ComponentScan("com.ycl")
注解驱动:@EnableWebMvc
视图解析器:ViewResolver【Bean】
视图控制器:addViewControllers
默认servlet:configureDefaultServletHandling.enable();
文件上传解析器:MultipartResolver【Bean】
拦截器:addInterceptors
异常处理:configureHandlerExceptionResolvers【bean】
只需要mybatis和数据区驱动。
两个配置文件使用selectOne发送请求
两个配置文件加上接口使用getMapper获取代理类,调用对应方法执行
解决mybatis核心配置文件。约束在官网拉取。
Conguration接口
环境:事务处理器和数据源
找到映射文件
propertis:引入外部资源【配合${}取数据】
优先级:1.方法参数。
优先级:2.外部文件引入。
优先级:3.标签里。】
settings:全局设置
mapUnderscoreToCamelCase:驼峰映射
jdbcTypeForNull:设置全局空值jdbc标识
lazyLoadingEnable:全局开启
aggressiveLazyLoading:关闭任何方法触发
cacheEnabled:全局缓存
typeAliases:给javaType起别名
1.直接指定。
2.包指定,别名为类名首字母小写或@Alias
typeHandler:类型处理器【源码】
plugins:拦截核心步骤【源码】
拦截Excutor。
拦截ParamenterHandler。
拦截StatementHandler。
拦截ResultSetHandler。
environments:环境配置
事务管理器
JDBC:jdbc的事务
MANAGED:容器事务
数据源
UNPOOL:不用池
POOL:使用池
JNDI:使用外部配置
databaseIdProvider:开启多数据库支持
mappers:找映射文件或注解
resource
url是全限定资源定位符
class是接口类的全限定类名。
package包下的所有映射文件或CRUD注解
objectFactory:对象工厂【创建结果对象时,通过该工厂实例化】
解决mybatis核心配置文件。约束在官网拉取。
mapper标注命名空间
CRUD的SQL语句标签
CRUD【@Select,@Insert,@Update,@Delete】
#{}是预编译参数
flushCache清除一级二级缓存
timeout超时时间
statementType选择语句类型【非预编译,预编译,存储过程】
databaseId数据库厂商标识
resultMap:结果集映射
sql:抽取公共SQL
cache:开启二级缓存
cache-ref:引用外部缓存配置
useCeneratedKeys:增加修改时生成值
keyProperty:主键值填充到属性
selectKey:增加修改【子标签】
keyProperty:替换增加修改字段值
resultType:返回值类型
order:增加修改之前或之后执行
resultType封装结果集类型
resultMap引用外部的resultMap标签
useCache结果给二级缓存保存,
fetchSize返回结果条数限定建议
resultSetType结果集指针策略
单个参数
直接取出:id=#{id}
多个参数
多个参数以arg0和param1作为key
参数起别名给arg0进行替换
POJO
属性名取值
Map
key取值
Collection
list和map都可以用collection作为key
list还可以用list作为key
数组
数组以array作为key
#和$
javaType
jdbcType
mode:存储过程
numericScale:数值范围
resultMap
typeHandler
jdbcTypeName
expression:未来扩展
List
resultType类型为元素
POJO
resultType类型是类
Map
Map的key是列名,value是对应值【此处和OPJO相似】
resultType是map类型
Map
Map的key是主键,value是对应对象
resultType类型为元素
@MapKey("id"):标识Map集合的key
映射类
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> </resultMap>
包含类属性
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> <result property="" column=""/>【属性类的属性表示】 </resultMap>
一对一关联对象
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> <association property="属性" javaType="属性类型"> <id property="" column=""/> <result property="" column=""/> </association> </resultMap>
一对一分步查询
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> <association property="属性" select="关联查询的命名空间+id" column="列值传递"/> </resultMap>【分步查询是简单查询】
一对多关联查询
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> <collection property="" ofType=""> <id property="" column=""/> <result property="" column=""/> </collection> </resultMap>
一对多分步查询
<resultMap id="userMap" type="user"> <id property="" column=""/> <result property="" column=""/> <collection property="属性" select="关联查询的命名空间+id" column="列值传递"/> </resultMap>【分步查询是简单查询】
鉴别器
<discriminator javaType=""> <case value=""></case> </discriminator>【满足条件才会加上规则】
延迟加载
lazyLoadingEnable:全局开启
aggressiveLazyLoading:关闭任何方法触发
fetch="lazy"局部懒加载
多值传递
column="{deptId=id}"
if
<if test=' '></if>
where
<where></where>包裹相当于where 1=1;
set
<set></set>包裹相当于去除尾部逗号
trim
<trim><trim>解决前缀和后缀规则
choose(when,otherwise)
<choose></choose>
<when test=""></when>
<otherwise></otherwise>
foreach
collection:集合
item:每一个遍历的元素
separator:每一个元素之间的分隔符
open:遍历结果开始字符
close:遍历结果结束字符
index:遍历List的时候是下标
遍历map
index:是key值
item:是value值
遍历多条sql语句【allowmultiqueryies=true】
遍历values的值
_parameter:
单个参数,这个内置参数就是它
多个参数,这个内置参数就是所有参数的map集合
_databaseId:
表示当前数据库
起别名之后,代表当前数据库的别名
参数拼接绑定 <bind name="_last" value="'%'+last+'%'"/>
不是同一个SqlSession
同一个SqlSession,查询条件不同
同一个SqlSession,执行了一次操作
同一个SqlSession,清除缓存了。【clearCache方法】
一级缓存关闭,就会存入二级缓存
cacheEnabled:关闭二级缓存
useCache:关闭SQL语句的二级缓存
flushCache:操作SQL刷新缓存
二级缓存
一级缓存
查询数据库
cacheEnabled:全局缓存
<cache/>:配置二级缓存
只需要encache和mybatis-encache依赖
<cache type="配置上Encache就行"/>
只需要mybatis-generator-core依赖。MyBatis Generator Core – MyBatis Generator Quick Start Guide
SqlSessionFactoryBuilder的build方法返回DefaultSqlSessionFactory
结合被解析对象返回XMLConfigBuilder
解析对象返回Configuration对象
CRUD标签解析:MappedStatements
接口信息:mapperRegistry:
执行build方法返回SqlSessionFactory
调用DefaultSqlSessionFactory(Configuration)
build.openSession()返回DefaultSqlSession对象
创建执行器this.configuration.newExecutor(tx, execType)
缓存执行器包装
excutor拦截器链【】【】【】
创建SqlSession对象new DefaultSqlSession(this.configuration, executor, autoCommit)
【】Executor的execType执行器类型取值【】
simple:简单
REUSE:重用
BATCH:批量
sqlSession.getMapper(UserMapper.class)
mapperRegistry根据接口类型获取MapperProxyFactory
创建MapperProxy对象
返回动态代理MapperProxy
mapper.findAll()
判断CRUD,判断返回结果集
参数转换成SQL参数
获取statement语句
SQL绑定成为完整句子
Query执行【二级缓存】
doQuery
创建StatementHandler
创建RoutingStatementHandler
paramer拦截器链【】【】【】
resultSet拦截器链【】【】【】
Statement拦截器链【】【】【】
处理预编译SQL语句
执行SQL语句
InterceptorChain遍历Interceptor
执行Interceptor的plugin(四个处理器对象)
实现Interceptor接口
plugin方法
return Plugin.wrap(target, this) 1. 获取签名映射 1. 获取Intercepts注解 2. 获取签名每一项Signature 3. 遍历每一个标签,Map<Class<?>, Set<Method>> 【签名中所有的类型和方法都封装到Map中】 2. 获取target类型 3. 获取所有接口 【目标类是所有接口和所有签名进行匹配】 4. 生成代理对象【匹配上生成增强对象,否则直接返回】 【给适配方法执行】 this.interceptor.intercept(new Invocation(this.target, method, args)) 调用当前的intercept方法
intercept方法
Invocation的proceed():是调用原始方法
拦截器类书写
@Intercepts(@Signature(type = StatementHandler.class,method ="batch",args = {})) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object proceed = invocation.proceed();//这里做增强 return proceed; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { Interceptor.super.setProperties(properties); } }
配置拦截器
<plugins> <plugin interceptor="com.ycl.interceptor.MyInterceptor"></plugin> </plugins>
目标方法在intercept方法中嵌套。
只需要pagehelper和jsqlparser两个依赖。
配置中添加拦截器PageInterceptor
调用
原生API:SqlSession(new RowBounds(0,10))【将RowBounds传到指定参数位置】
mapper方式一:查询之前使用PageHelper.startPage(0,10)
mapper方式二:查询之前使用PageHelper.offsetPage(0,10)
注解不需要xml处理:@Param("pageNum") pageNum和@Param("pageSize") pageSize
【只要请求参数中能取到这两个值就可以】
【PageInfo包装处理分页结果】
批量保存:BatchExcutor会让数据库保存预编译保存语句,修改参数值进行保存。
Spring中使用批量操作,注册SqlSessionTemplate【并且指定Excutor】
解决多个sql语句的集合。
调用statementType="CALLABLE"
语法:{call 存储函数(#{名称,mode=,jdbcType=})}
定义
实现TypeHandler接口或继承BaseTypeHandler类
@MapperType:定义java类型
@MapperJdbcType:定义jdbc类型
使用
使用方式一:自定义结果集,参数处理的时候【resultMap和#{id,typeHandler=xxxx}】
使用方式二:全局配置【handler使用类型处理器,javaType是某个类型时候使用】
只需要mybatisplus依赖。内部包含mybatis和mybatis-spring依赖。
【Mybatis3.5.0之后就不支持GlobalConfiguration了,支持yum】
前提条件mybatis和spring整合完成。
将SqlSessionFactoryBean修改成MybatisSqlSessionFactoryBean
Mapper接口继承BaseMapper<javaBean>接口
可以调用BaseMapper中的方法
方法
【增加】
insert:非空字段才会出现在sql语句中
insertAllColumn:所有的字段都会出现在sql语句中
【修改】
updatteById:非空字段才会出现在sql语句的修改字段中
updateAllColumnById:所有的字段都会出现在sql语句修改字段中
【查询】
selectById:传入序列化类型的id,id作为查询条件
selectOne:传入一个对象,非空字段作为条件
selectBatchIds:传入collection的id集合,id作为枚举查询条件
selectByMap:传入map集合,key=value作为条件
selectPage:传入的RowRounds和wrapper条件。逻辑分页查询
【删除】
deleteById:传入序列化类型的id,id作为条件
deleteByMap:传入map集合,key=value作为条件
deleteBatchIds:传入collection的id集合,id作为枚举查询条件
使用数据库的字段而不是java属性。EntityWrapper类
结构
wrapper和AbstractWrapper【抽象父类】
UpdateWrapper【查询】【删除】
QueryWrapper【修改】
【三元素:condition,column,param】
AbstractLambdaWrapper
LambdaUpdateWrapper
LambdaQueryWrapper
方式一
QueryWrapper qw= new QueryWrapper();
qw.eq();
【原始方式】
方式二
QueryWrapper<User> qw= new QueryWrapper();
qw.lambda().eq();
【使用Lambda表达式】
方式三
LambdaQueryWrapper<User> lqw= new LambdaQueryWrapper();
lqw.eq();
【使用Lambda表达式】
@TableId:主键策略IdType【value和列名一致】
AUTO:自增
NONE:用户自己输入
INPUT:用户自己输入
ASSIGN_ID:全局唯一ID,自动填充
ASSIGN_UUID:全局唯一ID,自动填充
@TableName:主要起别名
@TableField:字段
value:字段名映射
exist:是否存在表字段
核心API:GlobalConfiguration,加入到SqlSessionFactoryBean中。
驼峰映射:dbColumnUnderline
主键策略:idType
表的前缀:tablePrefix
插入修改获取返回主键,直接获取就可以。
MapperProxy:代理对象
SqlSessionFactory:会话工厂
Configuration:配置信息
MapperStatements:所有的SQL语句
BaseMapper的sql语句自动注入原理【AutoSqlInjector】
获取configuration中的sqlInjector配置(只能一个)
AutoSqlInjector的injectSql方法所有增强分发
最终用addMappedStatement方法【可以在该环节增强】模仿作业
LogicSqlInjector逻辑删除
将LogicSqlInjector注入到SqlSessionFacotry中
并且配置逻辑删除值,删除标签和非删除标签
@TableLogic逻辑删除delval表示逻辑删除标签
ArtiveRecord
实体类去继承Model类就可以使用实体自己的CRUD操作
需要velocity-engine-core【模板引擎】或freemark依赖
可以生成domain,mapper,mapper映射,还可以生成service,controller。
全局配置:GlobalConfig
数据源配置:DataSourceConfig
策略配置:StrategyConfig
包名配置:PackageConfig
整合配置:AutoGenerator
执行:autoGenerator.execute();
示例
public static void main(String[] args) { // 1.全局配置 GlobalConfig config = new GlobalConfig(); config.setActiveRecord(true) .setAuthor("YCL") .setOutputDir("D:\\mybatis-plus\\mpg\\src\\main\\java") .setFileOverride(true) .setIdType(IdType.AUTO) .setServiceName("%Service") .setBaseResultMap(true) .setBaseColumnList(true); // 2.设置数据源 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setDbType(DbType.MYSQL) .setDriverName("com.mysql.cj.jdbc.Driver") .setUrl("jdbc:mysql:///jdbc_template?serverTimezone=Asia/Shanghai") .setUsername("root") .setPassword("root"); // 3.策略配置 StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setCapitalMode(true) .setDbColumnUnderline(true) .setNaming(NamingStrategy.underline_to_camel) // .setTablePrefix("tb_") .setInclude("user"); // 4.包名配置 PackageConfig packageConfig = new PackageConfig(); packageConfig.setParent("com.ycl") .setMapper("mapper") .setService("service") .setController("controller") .setEntity("domain") .setXml("mapper"); // 5.整合配置 AutoGenerator autoGenerator = new AutoGenerator(); autoGenerator.setGlobalConfig(config) .setDataSource(dataSourceConfig) .setStrategy(strategyConfig) .setPackageInfo(packageConfig); // 6.执行 autoGenerator.execute(); }
分页插件:PaginationInteceptor
配置
将PaginationInteceptor插件注册
并且将插件传入到Configuration中
使用
创建一个page对象传入分页查询方法中【page是RowBounds的子类】
page就可以直接获取所有page信息
全表操作拦截
<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor"> <property name="stopProceed" value="true"/> </bean>
慢SQL处理
<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"> <property name="format" value="true"/> <property name="maxTime" value="1"/> </bean>
乐观锁插件
必须使用@Version标记版本 <bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"/>
元素据处理器接口MetaObjectHandler
注解填充@TableFile(fill=FieldFill.INSERT)
自定义公共字段填充器MetaObjectHandler子类
MP全局配置注入填充器
MybatisX代码生成器
MybatisX快速添加CRUD
Mvaen工具也可以叫做软件的安装配置。
Maven是apache的一个软件
需要配置JAVA_HOME
设置自身的MAVEN_HOME
mvn -v检测安装成功
bin:可执行命令
boot:Maven类加载器框架
conf:配置
lib:Maven所需要的依赖支持
LICENSE,NOTICE,README.tx:第三方软件介绍
局部setting.xml放在repository同目录下
本地缓存位置【settings:<localRepository>】
maven下载镜像
maven选用jdk版本
镜像 <mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror> 或者 <mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
JDK版本 <profile> <id>jdk1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>
maven软件位置
settings.xml位置
localRepository位置
pom.xml文件生成对应的pom对象
依赖管理模型,本地仓库管理jar包
私服仓库管理jar包
中央仓库下载jar包
Maven构建生命周期插件
依赖管理工具
依赖构建工具
依赖分享工具
自动部署环节
1. 依赖管理工具 【原来】使用jar包依赖,将jar包放入WEB-INF/libs下面 【现在】 1. Maven中央仓库下载到Maven本地仓库 2. 本地仓库导入jar包 2. 依赖构建工具 打包成jar包或war包 3. 依赖分享工具 Nexus私服传递依赖 4. 自动部署环节 从Maven推送到Git远程仓库 持续集成Jenkins 部署云原生kubernates到Docker实例
jar包不规范
jar包之间依赖关系
必须存储到指定位置lib
groupId:com.公司.主业务.子业务
artifactId:产品-模块
version:主版本.次版本.修订号.里程碑版本【API修改,功能增强,bug修复,RELEASE】
package:jar,war,pom【普通工程,web工程,父工程不打包】
直接依赖:配置文件中写了的依赖
间接依赖:配置文件的依赖,这个依赖还有依赖
依赖越直接层级越浅,优先级越高
依赖相同层级,前面配置的优先级高
同一个依赖配置,后面的依赖覆盖前面的依赖
<optional>true</optional>隐藏依赖不被传递
排除依赖<exclusion>GAV</exclusion>
【模块只有打包之后才能用】
Scope
主程序
测试程序
是否参与打包
选项
compile:主代码,测试,打包【log4j】
test:只测试【junit】
runtime:只打包【jdbc】
provided:不打包【servlet-api】
不打包pom
<modules>来引入聚合的项目【../项目名:同级目录】
模块继承<parent>GAV加上<relativePath>父工程pom文件</relativePath></parent>
父工程的<dependencyManager>管理依赖版本
定义:<properties><spring.version>5.2.0.RELEASE</spring.version></properties>
使用:${spring.version}
还有:Maven内置属性,setting属性,java系统属性,env环境变量【mvn help:system】
<resources>\将pom配置属性也用到properties【指向指定的resources目录】【过滤拦截true】</resources>
定义:<profile>
<id>dep_env
<activation>true默认配置
使用:Command line:install -P dep_env
插件
使用IDEA的时候,构建是IDEA帮我们构建的。
Maven构建:清理,编译,测试,报告,打包,部署。
插件有包在官网查看
clean阶段
pre-clean:清理之前
clean:清理
post-clean:清理之后
default阶段
validata:校验
initialize:初始化
generate-sources:生成源码
process-sources:处理源码
generate-resources:生成源文件
process-resources:处理源文件
compile:源代码【编译】
process-classes:处理类文件
generate-test-sources:生成测试源码
process-test-sources:处理测试源码
generate-test-resources:生成测试源文件
process-test-resources:处理测试源文件
test-compile:测试源码【编译】
process-test-compile:处理测试类文件
test:执行测试代码【测试】
prepare-package:准备打包
package:【打包】
pre-integration-test:集成测试前
integration-test:集成测试
post-integration-test:集成测试后
verify:验证
install:打包上传到本地库【安装】
deploy:打包上传到远程库【部署】
site阶段
pre-site:生成站点文件前
site:生成站点文件
post-site:生成站点文件后
site-deploy:生成站点文档部署到服务器【服务器】
1. 原始目录【项目】 1. src【源代码】之后会存放到WEB-INF下 2. web【静态文件】 1. WEB-INF【不被直接访问的资源】 1. libs【依赖包】 2. web.xml【配置文件】 2. 编译目录【out/artifacts/项目war包】 1. WEB-INF 1. classes 2. libs 3. web.xml
pom.xml
src(main,test)
main(java,reources)
webapp
WEB-INF
web.xml
index.html
test(java,resource)
解决场景
整体模块未开发完毕
模块某个功能为开发完毕
单个功能调试导致其他功能失败
打包加速
实现
mvn install -D skipTests【跳过所有测试】
点击test横线也可以跳过
只需要spring-boot-starter-web一个依赖
提供大量默认配置
内嵌web服务器
监控健康检查
pom文件
parent:spring-boot-starter-parent
dependency:spring-boot-starter
主类
@SpringBootApplication
SpringApplication.run(主类,参数);
最顶层父项目管理了依赖版本【主要依赖】
直接父项目管理插件版本【主要插件】
web场景启动器:spring-boot-starter-web
打jar包插件:spring-boot-maven-plugin
java -jar springboot的jar包
main方法中SpringApplication运行返回的是IOC容器
spring-boot-autoconfigure
注解@SpringBootApplication
@SpringBootConfiguration
Configuration
proxyBeanMethods设置true:单例【Full模式】
proxyBeanMethods设置false:多例【Lite模式】
@EnableAutoConfiguration【自动配置选取】
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)【将启动类所在包下的组件全部导入到容器】
@Import(AutoConfigurationImportSelector.class)【筛选导入】
autoconfigure的META-INF/spring-factories文件的127个场景启动器
@Condition满足才生效,筛选组件
@ComponentScan
组件配置
@Import:引入配置类
@Conditional:条件注入组件
@ImportResource:导入资源【将xml加入进去】
@ConfigurationProperties:组件才能使用配置绑定【核心配置】
@EnableConfigurationProperties:有注入到容器和配置绑定【核心配置】
配置特性
自定义会覆盖
ServletWebServerFactoryCustomizer自定义器
实体类的相关方法。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
lombok插件
相关注解
@Slf4j
@Data
@Getter
@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
@AllArgsConstructor:全参构造
@NoArgsConstructor:无参构造
热部署
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
【k: v】基本语法冒号后面有空格,不能tab缩进代替
缩进代表上下级关系
注释#
单引号转义
双引号不转义
对象,map
k: {k1: v1,k2: v2,k3: v3}
k: k1: v1 k2: v2 k3: v3
数组,单列集合
k: {v1,v2,v3}
k: -v1 -v2 -v3
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency>
WebMvcAutoConfiguration
静态资源位置
默认classpath下:
/static
/public
/resources
/META-INF/resources
因为它使用ResourceHttpHandler
修改资源位置:spring.resource.static-locations=classpath/xxx/xx
静态资源访问
默认访问:/**
修改默认路径:spring.mvc.static-path-pattern=/xxx/xx
自定义静态资源路径会影响欢迎页面
默认在静态资源中找到:index.html
默认找到template处理:/index
默认图标:favicon.ico资源
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。