#Ajax和Axios
Ajax 即"Asynchronous JavaScript And XML"(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的网页开发技术,可以给服务器发送请求,并获取服务器响应的数据。无需重新加载整个网页的情况下,能够更新部分网页的技术。
Ajax 应用程序的优势在于:
- 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用
- Ajax 引擎在客户端运行,承担了一部分本来由服务器承担的工作,从而减少了大用户量下的服务器负载。
Axios 是一种异步请求,对原生的Ajax进行了封装,简化书写,快速开发,安装 npm install axios --save 即可使用,请求中包括 get,post,put, patch ,delete 等五种请求方式。
<script>
// 引入 axios
import Axios from 'axios'
export default {
methods: {
testAxios() {
const url = 'https://www.baidu.com/'
Axios.get(url).then(response => {
if (response.data) {
console.log(response.data)
}
}).catch(err => {
alert('请求失败')
})
}
}
}
</script>
Maven
是一款管理和构建java项目的工具。
什么是坐标?
Maven 中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置。使用坐标来定义项目或引入项目中需要的依赖。
Maven 坐标主要组成
- groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.itheima)
- artifactId:定义当前Maven项目名称(通常是模块名称,例如 order-service、goods-service)
- version:定义当前项目版本号
生命周期
Maven中有3套相互独立的生命周期:
- clean:清理工作。
- default:核心工作,如:编译、测试、打包、安装、部署等。
- site:生成报告、发布站点等。
上述每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行。
Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际工作。**在Maven的设计中,实际任务(如源代码编译)都交由插件来完成。**这么多生命周期阶段,其实我们常用的并不多,主要关注以下几个:
- clean:移除上一次构建生成的文件(clean自己是一套,下面四个是一套生命周期)
- compile:编译项目源代码
- test:使用合适的单元测试框架运行测试(junit)
- package:将编译后的文件打包,如:jar、war等
- install:安装项目到本地仓库
在maven中,可以在父工程的pom文件中通过 来统一管理依赖版本。子工程引入依赖时,无需指定 版本号,父工程统一管理。变更依赖版本,只需在父工程中统一变更。
dependencyManagement 与 dependencies的区别是什么?
- 是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
- 是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)
Tomcat
Tomcat是Apache 的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范。Tomcat 也被称为 Web容器、Servlet容器。Servlet程序需要依赖于 Tomcat才能运行。
Web服务器是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。还能够部署web项目,对外提供网上信息浏览服务。
Spring
事务管理
事务 是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过 binlog 或者 redo log 实现的。
spring 事务实现主要有两种方法
1、编程式,beginTransaction()、commit()、rollback()等事务管理相关的方法
-
开启事务(一组操作开始前,开启事务):start transaction / begin ;
提交事务(这组操作全部成功后,提交事务):commit ;
回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;
2、声明式,利用注解 Transactional 或者 aop 配置
@Transactional位置放在业务(service)层的方法上、类上、接口上。能够将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务。
IOC
控制反转,Inversion Of Control,简称IOC。
对象的创建控制权由程序自身转移到外部(IOC容器),并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。最直观的表达就是,IOC 让对象的创建不用去 new 了,可以由 spring 根据我们提供的配置文件自动生产,我们需要对象的时候,直接从 Spring 容器中获取即可。这种思想称为控制反转。
依赖注入: Dependency Injection,简称DI。和控制反转是同一个概念的不同角度的描述,即程序在运行时依赖 IOC 容器来动态注入对象依赖的资源。
Spring 的 IOC 有三种注入方式 :构造器注入, setter 方法注入, 根据注解注入。
- @Autowired注解,默认是按照类型进行,因此不能存在多个相同类型的bean
- 通过以下几种方案来解决:@Primary@Qualifier@Resource
- @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。@Autowired 默认是按照类型注入,而@Resource默认是按照名称注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean。
- 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用四个注解(@Component、@Controller,@Service,@Repository)都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
- 前面声明bean的四大注解,要想生效,还需要被组件扫描注解 扫描。@ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。
AOP
Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect)。
作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)
实现:动态代理是面向切面编程最主流的实现。
SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。
Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理:
(1) JDK 动态代理只提供接口代理,不支持类代理,核心 InvocationHandler 接口和Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
(2) 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。
核心概念
- 连接点:JoinPoint,可以被AOP控制的方法(封装了连接点方法在执行时的相关信息)。例如:入门程序当中所有的业务方法都是可以被aop控制的方法。
- 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用。常会通过一个切入点表达式来描述切入点
- 切面:Aspect,描述通知与切入点的对应关系(即通知+切入点)。通过切面就能够描述当前aop程序需要针对于哪个原始方法,在什么时候执行什么样的操作。切面所在的类,我们一般称为切面类(被@Aspect注解标识的类)
- 目标对象:Target,通知所应用的对象。
通知类型
- @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
- @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值。
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行
通知顺序
不同切面类中,默认按照切面类的类名字母排序:
- 目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
用 @Order(数字) 加在切面类上来控制顺序:
- 目标方法前的通知方法:数字小的先执行
- 目标方法后的通知方法:数字小的后执行
切入点表达式
切入点表达式:
-
描述切入点方法的一种表达式
-
作用:主要用来决定项目中的哪些方法需要加入通知
-
常见形式:
- execution(……):根据方法的签名来匹配
- @annotation(……) :根据注解匹配(Log是自定义的注解全类名)
连接点
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
- 对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
- 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型
SpringMVC
SpringMVC 是一个基于 Java 的实现了 MVC 设计模式的请求驱动类型的轻量级 Web框架,通过把 Model,View,Controller 分离,将 web 层进行职责解耦,把复杂的 web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
主要组件
前端控制器 DispatcherServlet:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
处理器映射器 HandlerMapping:根据请求的 URL 来查找 Handler
处理器适配器 HandlerAdapter:负责执行 Handler
处理器 Handler:处理业务逻辑的 Java 类
视图解析器 ViewResolver:进行视图的解析,根据视图逻辑名将 ModelAndView 解析成真正的视图(view)
视图 View:View 是一个接口, 它的实现类支持不同的视图类型,如 jsp,freemarker,pdf 等等
SpringMVC 的执行流程以及各个组件的作用
1.用户发送请求到前端控制器(DispatcherServlet)
2.前端控制器( DispatcherServlet )收到请求调用处理器映射器(HandlerMapping),去查找处理器(Handler)
3.处理器映射器(HandlerMapping)找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
4.前端控制器(DispatcherServlet)调用处理器映射器(HandlerMapping)
5.处理器适配器(HandlerAdapter)去调用自定义的处理器类(Controller,也叫后端控制器)。
6.自定义的处理器类(Controller,也叫后端控制器)将得到的参数进行处理并返回结果给处理器映射器(HandlerMapping)
7.处 理 器 适 配 器 ( HandlerAdapter ) 将 得 到 的 结 果 返 回 给 前 端 控 制 器(DispatcherServlet)
8.DispatcherServlet(前端控制器) 将ModelAndView传给视图解析器(ViewReslover)
9.视图解析器(ViewReslover)将得到的参数从逻辑视图转换为物理视图并返回给前端控制器(DispatcherServlet)
10.前端控制器(DispatcherServlet)调用物理视图进行渲染并返回
SpringMVC 支持的转发和重定向的写法
1)转发:
forward 方式:在返回值前面加"forward:“,比如forward:user.do?name=method4”
2)重定向:
redirect 方式:在返回值前面加 redirect:, 比如"redirect:http://www.baidu.com
SpringMVC 统一异常处理的思想和实现方式
使用 SpringMVC 之后,代码的调用者是 SpringMVC 框架,也就是说最终的异常会抛到框架中,然后由框架指定全局异常处理类进行统一处理
方式一: 创建一个自定义异常处理器(实现 HandlerExceptionResolver 接口),并实现里面的异常处理方法,然后将这个类交给 Spring 容器管理
方式二: 在类上加注解(@ControllerAdvice)表明这是一个全局异常处理类,在 方 法 上 加 注 解 (@ExceptionHandler), 在 ExceptionHandler 中 有 一 个value 属性,可以指定可以处理的异常类型
SpringMVC 中文件上传的使用步骤是什么样的? 前台三要素是什么?
文件上传步骤:
1.加入文件上传需要的 commons-fileupload 包
2.配置文件上传解析器,springmvc 的配置文件的文件上传解析器的 id 属性必须为multipartResolver
3.后端对应的接收文件的方法参数类型必须为 MultipartFile,参数名称必须与前端的 name 属性保持一致
文件上传前端三要素:
1.form 表单的提交方式必须为 post
2.enctype 属性需要修改为:multipart/form-data
3.必须有一个 type 属性为 file 的 input 标签,其中需要有一个 name 属性;如果需要上传多个文件需要添加 multiple 属性
Springboot
是 Spring 的子项目,主要简化 Spring 开发难度,去掉了繁重配置,提供各种启动器,可以让程序员很快上手,节省开发时间。
基于Springboot开发的web应用程序,内置了tomcat服务器,当启动类运行时,会自动启动内嵌的tomcat服务器。
请求
请求参数
简单参数
请求参数名与形参变量名相同,定义形参即可接收参数,会自动进行类型转换。如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。
@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。 如果该参数是可选的,可以将required属性设置为false。
实体参数
请求参数名与形参对象属性名相同,定义POJO接收即可(复杂的按照对象层次结构关系即可接收嵌套POJO属性参数)
数组集合参数
数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
集合参数:请求参数名与形参集合名称相同且请求参数为多个,且用 @RequestParam 绑定参数关系
日期参数
使用 @DateTimeFormat 注解完成日期参数格式转换
JSON 参数
JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识
路径参数
通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数
Bean管理
获取bean
默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。
主动从IOC容器中获取到bean对象的3种常用方式:
-
根据name获取bean
Object getBean(String name)
-
根据类型获取bean
<T> T getBean(Class<T> requiredType)
-
根据name获取bean(带类型转换)
<T> T getBean(String name, Class<T> requiredType)
bean作用域
在前面我们提到的IOC容器当中,默认bean对象是单例模式(只有一个实例对象)。那么如何设置bean对象为非单例呢?需要设置bean的作用域。
在Spring中支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
prototype | 每次使用该bean时会创建新的实例(非单例) |
request | 每个请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
可以借助Spring中的@Scope注解来在bean上进行配置
第三方bean
之前我们所配置的bean,像controller、service,dao三层体系下编写的类,这些类都是我们在项目当中自己定义的类(自定义类)。当我们要声明这些bean,也非常简单,我们只需要在类上加上@Component以及它的这三个衍生注解(@Controller、@Service、@Repository),就可以来声明这个bean对象了。
但是在我们项目开发当中,还有一种情况就是这个类它不是我们自己编写的,第三方提供的类是只读的。无法在第三方类上添加@Component注解或衍生注解,是我们引入的第三方依赖当中提供的。后续用@AutoWired注入即可使用第三方类。
解决方案1:在启动类上添加@Bean标识的方法
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
public SAXReader saxReader(){
return new SAXReader();
}
}
说明:以上在启动类中声明第三方Bean的作法,不建议使用(项目中要保证启动类的纯粹性)
解决方案2:在配置类中定义@Bean标识的方法
- 如果需要定义第三方Bean时, 使用@Configuration单独定义一个配置类,并在类里面用@Bean定义第三方类
@Configuration //配置类 (在配置类当中对第三方bean进行集中的配置管理)
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名
public SAXReader reader(DeptService deptService){
System.out.println(deptService);
return new SAXReader();
}
}
在方法上加上一个@Bean注解,Spring 容器在启动的时候,它会自动的调用这个方法,并将方法的返回值声明为Spring容器当中的Bean对象。
注意事项 :
通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
SpringBoot原理
起步依赖starter
如果我们使用了SpringBoot,就不需要像上面这么繁琐的引入依赖了(spring-webmvc依赖、Servlet基础依赖、jackson-databind依赖:JSON处理工具包、aop依赖、aspect依赖,项目中所引入的这些依赖,还需要保证版本匹配,否则就可能会出现版本冲突问题)。我们只需要引入一个依赖就可以了,那就是web开发的起步依赖:springboot-starter-web。起步依赖使用starter 启动器
为什么我们只需要引入一个web开发的起步依赖,web开发所需要的所有的依赖都有了呢?
- 因为Maven的依赖传递。
在SpringBoot给我们提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters)。
比如:springboot-starter-web,这是web开发的起步依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过Maven的依赖传递进来。
结论:起步依赖的原理就是Maven的依赖传递。
自动装配
当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
自动配置的核心就在@SpringBootApplication注解上,SpringBootApplication这个注解底层包含了3个注解,分别是:
-
@SpringBootConfiguration
- 使用了@Configuration,表明SpringBoot启动类就是一个配置类。@Indexed注解,是用来加速应用启动的(不用关心)。
-
@ComponentScan
- 是用来进行组件扫描的,扫描启动类所在的包及其子包。
-
@EnableAutoConfiguration
@EnableAutoConfiguration这个注解才是自动配置的核心。
- 以@EnableXxxx(不止是@EnableAutoConfiguration,其他第三方依赖也提供@EnableXxxx,用于自行加到启动类上,装配bean到IOC)开头的注解的底层,封装了一个@ import 注解,它里面指定了一个类,是 ImportSelector 接口的实现类。在实现类当中,我们需要去实现 ImportSelector 接口当中的一个方法 selectImports 这个方法。将配置文件中定义的配置类做为selectImports()方法的返回值返回。这个方法的返回值代表的就是我需要将哪些类交给 spring 的 IOC容器进行管理。
- 此时selectImports()方法会去读取两份配置文件,一份儿是 spring.factories,另外一份儿是 autoConfiguration.imports。而在 autoConfiguration.imports 这份文件当中,它就会去配置大量的自动配置类(类名XxxxAutoConfiguration,配置类上添加了注解@AutoConfiguration,这个注解用于自动装配,底层就是@Configuration)。
- 而前面我们也提到过这些所有的自动配置类当中,所有的 bean都会加载到 spring 的 IOC 容器当中吗?其实并不会,因为这些配置类当中,在声明 bean 的时候,通常会加上这么一类@Conditional 开头的注解(和@Bean并列使用)。这个注解就是进行条件装配。所以SpringBoot非常的智能,它会根据 @Conditional 注解来进行条件装配。只有条件成立,它才会声明这个bean,才会将这个 bean 交给 IOC 容器管理。
在Spring框架的生态中,对web程序开发提供了很好的支持,如:全局异常处理器、拦截器这些都是Spring框架中web开发模块所提供的功能,而Spring框架的web开发模块,我们也称为:SpringMVC
SpringMVC不是一个单独的框架,它是Spring框架的一部分,是Spring框架中的web开发模块,是用来简化原始的Servlet程序开发的。
外界俗称的SSM,就是由:SpringMVC、Spring Framework、Mybatis三块组成。
基于传统的SSM框架进行整合开发项目会比较繁琐,而且效率也比较低,所以在现在的企业项目开发当中,基本上都是直接基于SpringBoot整合SSM进行项目开发的。
到此我们web后端开发的内容就已经全部讲解结束了。
常用注解
1.@Component(任何层) @Controller @Service @Repository(dao): 用于实例化对象
2.@Scope : 设置 Spring 对象的作用域
3.@PostConstruct @PreDestroy : 用于设置 Spring 创建对象在对象创建之后和销毁之前要执行的方法
4.@Value: 简单属性的依赖注入
5.@Autowired: 对象属性的依赖注入
6.@Qualifier: 要和@Autowired 联合使用,代表在按照类型匹配的基础上,再按照名称匹配。
7.@Resource 按照属性名称依赖注入
8.@ComponentScan: 组件扫描
9.@Bean: 表在方法上,用于将方法的返回值对象放入容器
10.@PropertySource: 用于引入其它的 properties 配置文件
11.@Import: 在一个配置类中导入其它配置类的内容
12.@Configuration: 被此注解标注的类,会被 Spring 认为是配置类。Spring 在启动的时候会自动扫描并加载所有配置类,然后将配置类中 bean 放入容器
13.@Transactional 此注解可以标在类上,也可以表在方法上,表示当前类中的方法具有事务管理功能。
1.@RequestMapping(GET、POST、DELETE):用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
2.@RequestBody:注解实现接收 http 请求的 json 数据,将 json 转换为 java 对象。
3.@ResponseBody:注解实现将 controller 方法返回对象转化为 json 对象响应给客户。
4.@PathVariable 用户从 url 路径上获取指定参数,标注在参数前 @PathVariabel(" 要获取的参数名")。
5.@RequestParam: 标注在方法参数之前,用于对传入的参数做一些限制,支持三个属性:
- value:默认属性,用于指定前端传入的参数名称
- required:用于指定此参数是否必传
- defaultValue:当参数为非必传参数且前端没有传入参数时,指定一个默认值
6.@ControllerAdvice 标注在一个类上,表示该类是一个全局异常处理的类。
7.@ExceptionHandler(Exception.class) 标注在异常处理类中的方法上,表示该方法可以处理的异常类型。
登录校验
登录校验,指的是我们在服务器端接收到浏览器发送过来的请求之后,首先我们要对请求进行校验。先要校验一下用户登录了没有,如果用户已经登录了,就直接执行对应的业务操作就可以了;如果用户没有登录,此时就不允许他执行相关的业务操作,直接给前端响应一个错误的结果,最终跳转到登录页面,要求他登录成功之后,再来访问对应的数据。
浏览器与服务器之间进行交互,基于HTTP协议,因为HTTP协议是无状态的,两次请求之间是独立的,所以在执行其他业务操作时是无法判断这个员工到底登陆了没有。
实现登录校验的实现思路可以分为两部分:
- 在员工登录成功后,需要将用户登录成功的信息存起来,记录用户已经登录成功的标记。使用会话技术。
- 在浏览器发起请求时,需要在服务端进行统一拦截,拦截后进行登录校验。使用统一拦截技术。
会话
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
会话跟踪方案:
- Cookie(客户端会话跟踪技术)
- 数据存储在客户端浏览器当中
- Session(服务端会话跟踪技术)
- 数据存储在储在服务端
- 令牌技术
三者优劣
- Cookie
- 优点:HTTP协议中支持的技术
- 缺点: 移动端APP无法使用Cookie。 不安全,用户可以自己禁用Cookie。 Cookie不能跨域
- Session(底层基于 Cookie 实现。)
- 优点:存储在服务端,安全
- 缺点: 服务器集群环境下无法直接使用Session。Cookie的缺点他也都有
- JWT
- 优点: 支持PC端、移动端 。解决集群环境下的认证问题 。减轻服务器端存储压力。
- 缺点:需要自己实现
JWT
全称:JSON Web Token
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
组成:
- 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
- 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
JWT是如何将原始的JSON格式数据,转变为字符串的呢?
生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。还有一个等号,它是一个补位的符号
需要注意的是Base64是编码方式,而不是加密方式。
JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。
统一拦截
Filter
概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
过滤器执行流程是:请求 --> 放行前逻辑 --> 放行 --> 资源 --> 放行后逻辑
放行操作:filterChain.doFilter(servletRequest,servletResponse);
一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。
Interceptor
概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
执行流程如下
-
当访问web应用时,过滤器会拦截。它会先执行放行前的逻辑,然后执行filterChain.doFilter放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的controller当中的接口方法。
-
Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。
-
当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行
preHandle()
方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。 -
在controller当中的方法执行完毕之后,再回过来执行
postHandle()
这个方法以及afterCompletion()
方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。
File与Interceptor区别
接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。