JavaWeb 学习笔记
D01 web及HTML#
Web网站的工作流程:路由器 - 前端服务器 - 后端Java程序 - 数据库服务器 = 前后端分离开发
前端Web开发
- HTML、CSS、JavaScript
- Vue、Element、Nginx
后端Web开发
- Maven
- SpringBoot Web
- MySQL
- SpringBoot Mybatis
Web标准:三个组成部分 HTML(网页的结构)、CSS(网页的表现)、javaScript(网页的行为)
HTML#
- 结构标签:html - head body
- 特点:不区分大小写、属性值单双引号都可以、语法松散
CSS#
CSS引入方式:行内/内嵌/外联(写在单独的css文件中)
<link rel="stylesheet" href="style.css">
CSS 颜色表示形式:关键字/rgb(0,0,0)/十六进制表示#ff0000
CSS 选择器:元素选择器(元素名称 element)/ID选择器(元素ID #time)/类选择器(元素CLASS .cls)
超链接#
<a href="" target="_self or _blank">
- _self: 当前页面,默认
- _blank: 新页面
- _parent: 现在已经不常用,在父级框架打开
- _top: 现在已经不常用,在整个窗口中打开链接
text-decoration: none; 指定文本装饰。
视频#
- src: 视频的url
- controls: 显示播放控件
- width
- height
音频#
- src: 音频的url
- controls: 显示播放控件
段落#
<p> 划分段落。
- text-indent: 首行缩进
- text-align: 文本对齐设置
文本加粗#
<b> / <strong>
HTML页面的整体布局#
盒子模型:内容区域content、内边距区域padding、边框区域border、外边距区域margin
div标签#
- 一行只显示一个
- 宽度默认是父元素的宽度
- 可以设置宽高
span标签#
- 一行可以显示多个
- 宽度和高度默认由内容撑开
- 不可以设置宽高
边距元素#
顺时针 - 上右下左
表格标签#
- table: 定义表格整体
- tr: 表格的行
- td: 表格单元格,表头则为th
表单标签#
form -> action/method
input: 表单项,通过type控制输入形式select: 下拉列表textarea: 文本域input type=submit: 提交按钮
能采集数据必须有内部属性name
label标签,聚焦区域全部元素;单选/多选按钮一组内需要有相同的name;提交的为value值
D02 JS和Vue#
JavaScript是跨平台、面向对象的脚本语言,是用来控制网页行为的,使得网页可交互。
JS的引入方式#
- 内部脚本
<script></script> - 外部脚本
<script src=".."></script>(不能自闭合)
JS的基础语法#
书写语法#
- 区分大小写
- 每行结尾的分号可有可无,但建议加上
// 注释/* 注释 */
输出语句
window.alert()写入警告框document.write()写入HTML输出console.log()写入浏览器控制台
变量#
- (const) var/let 声明变量,let作用于块级作用域,var作用于函数作用域 const表示只读
- js是弱类型语言,变量可以存放不同类型的值
- var定义的变量可以重复定义(声明),let则不行
数据类型、运算符、流程控制#
- 原始类型:number、string、boolean、null、undefined
typeof [var]获取数据类型
运算符
- 算数运算符
- 赋值运算符
- 比较运算符: === 全等运算符,不会进行类型转换; == 会进行类型转换
- 逻辑运算符
- 三元运算符
类型转换
parseInt()字符串转换为数字,若字面值不是数字,则转为NaN- 0和NaN转为boolean为false,其它为true
流程控制语句
- if…else…
- switch
- for
- while
- do…while
JS的函数#
被用来执行特定任务的代码块。
function functionName(参数1, 参数2){ // 代码 }var functionName = function(参数1, 参数2){ // 代码 }
JS的对象#
- Array String JSON
- BOM对象: 浏览器封装的对象模型
- DOM对象: 文档对象模型
Array#
var 变量名 = new Array(元素列表)var 变量名 = [元素列表]
相当于java中的集合,长度可变(直接赋值即可)、类型可变
- 属性:array.length
- 方法:forEach() 遍历一遍有值的元素、push() 将新元素添加到末尾并返回新的长度、splice() 删除元素
ES6 箭头函数 (e) => {...}
String#
var 变量名 = new String("...")var 变量名 = "..."属性:string.length
方法:charAt() 返回在指定位置的字符、indexOf() 检索字符串、trim() 去除字符串两边的空格、substring() 截取子字符串
JSON#
var jsObject = JSON.parse(userStr)var jsonStr = JSON.stringify(jsObject)
BOM#
- window 浏览器窗口对象
- history、location、navigator -
location.href - alert()、confirm()、setInterval()、setTimeout()
- history、location、navigator -
- Navigator 浏览器对象
- Screen 屏幕对象
- History 历史记录对象
- Location 地址栏对象
DOM#
封装对应对象:
- Document: 整个文档对象
- Element: 元素对象
- Attribute: 属性对象
- Text: 文本对象
- Comment: 注释对象

JS的事件监听#
事件:发生在HTML元素上的事情:按钮被点击/鼠标移动到元素上/按下键盘按键。
绑定方式#
- 通过HTML标签中的事件属性绑定
onclick="on()" - 通过DOM元素属性绑定
document.getElementById('btn').onclick = function(){}
常见事件#

Vue#
基于MVVM(Model-View-ViewModel)思想,实现数据双向绑定的前端框架。
插值表达式#
- 形式
{{ 表达式 }} - 内容可以是:变量、三元运算符、函数调用、算术运算
常用指令#
指令:HTML标签上带有v-前缀的特殊属性,不同指令具有不同含义
- v-bind 为HTML标签绑定属性值
- v-model 在表单元素上创建双向数据绑定
- v-on 为HTML标签绑定事件
- v-if 条件性渲染某元素
- v-else-if
- v-else
- v-show 根据条件展示某元素
- v-for 列表渲染
// 绑定的数据变量必须在数据模型中声明。 eg.
<a v-bind:href="url">AAA</a>/<a :href="url">AAA</a>::为属性绑定数据模型url<input type="text" v-model="url">:绑定表单元素,输入的数据会自动绑定到url上<input type="button" value="按钮" v-on:click="handle()"/<input type="button" value="按钮" @click="handle()":为HTML标签绑定事件<span v-show="age <= 35">年轻人</span>:条件判定(只通过display判断是否展示)<div v-for="(addr, index) in addrs">{{ addr }}</div>:遍历数组
生命周期#
生命周期:一个对象从创建到销毁的整个过程。

mounted字段对Java后端最重要。
D03 Ajax和Element#
Ajax#
Ajax - 异步的JavaScript和XML。作用:数据交换、异步交互。
原生Ajax#
- 准备数据
- 创建XMLHttpRequest对象
- 向服务器发送请求
4,获取服务器响应数据
Axios#
- 引入Axios的js文件
- 使用Axios发送请求,并获取响应结果
1 | |
前后端分离开发#
需求分析 - 接口定义(API接口文档) - 前后端并行开发 - 测试 - 前后端联调测试
前端工程化#
前端开发:模块化(JS\CSS)、组件化(UI结构\样式\行为)、规范化(目录结构\编码\接口)、自动化(构建\部署\测试)
Vue的目录结构#
node_modules整个项目的依赖结构public存放项目的静态文件src存放项目源代码src/assets静态资源src/components可复用的组件src/router/路由配置src/views/视图组件(页面)src/App.vue入口页面(根组件)src/main.js入口js文件package.json存放项目基本信息及依赖资源vue.config.js存放vue配置信息
Element#
案例#
- 创建页面,完成页面的整体布局规划。
- 布局中各个部分的组件实现。
- 列表数据的异步加载,并渲染展示。
Vue路由#
前端路由:URL中的hash与组件之间的对应关系。
Vue Router 是Vue的官方路由。由VueRouter(路由器类,维护路由表)、<router-link>(请求链接组件)、<router-view>(动态视图组件,用来渲染)
打包部署#
打包:执行脚本build,最终文件会在dist目录下生成。将dist目录内容使用nginx部署即可。
D04 Maven及Web入门#
Maven是一款用于管理和构建Java项目的工具。
- 依赖管理,管理项目依赖的资源、避免版本冲突
- 统一项目结构
- 标准化的项目构建流程
需要使用的架包只需要在pom.xml(Project Object Model)中声明依赖即可。
Maven的介绍#
仓库:用于存储资源,管理各种jar包。本地仓库/中央仓库/远程仓库。
bin\存放可执行文件conf\存放maven的配置文件lib\maven本身的依赖
IDEA集成Maven#
- 配置Maven环境
- 创建Maven项目
- 导入Maven项目
Maven坐标#
:资源的唯一标识,通过坐标可以唯一定位资源位置。可以使用坐标来定义项目或引入项目中需要的依赖。
坐标组成
- groupId: 项目隶属组织名称,通常为域名反写
- artifactId: 当前项目名称/模块名称
- version: 项目版本号
导入Maven项目#
- 打开IDEA,选择右侧Maven面板,点击+号,选中对应项目的pom.xml文件,打开即可。
- File - Project Structure - + - Import Module - + - pom.xml。
依赖管理#
依赖配置#
<dependencies> 标签中的若干个 <dependency> 子标签。
依赖传递#
依赖具有传递性。
- 直接依赖:在当前项目中通过依赖配置建立的依赖关系。
- 间接依赖:当前项目间接依赖其它资源。
排除依赖:在项目中主动断开依赖的资源。目的:减少版本冲突、排除不需要的实现、减少安全漏洞、减少包体积
<exclusions> 标签,放置于 <dependency> 内部即可,引用方法与依赖同理,但无需定义版本号。
依赖范围#
依赖的jar包在默认情况下全局可用,可通过<scope>...</scope>设置作用范围。取值:compile/test(仅测试)/provided(主程序和测试程序)/runtime(测试程序和打包)
maven的生命周期#
Maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一。
- clean: 清理工作。(- clean)
- default: 核心工作。(- compile test package install)
- site: 生成报告、发布站点等。
主要需要注意的阶段
- clean 移除上一次构建生成的文件
- compile 编译项目源代码
- test 使用合适的单元测试框架进行测试
- package 将编译后文件打包
- install 安装项目到本地仓库
在同一套生命周期中,运行后面的阶段时,前面的阶段都会运行。
- IDEA运行:直接在idea中双击对应阶段运行
- CMD运行:
mvn xxx
在idea中可手动跳过某个阶段。
SpringBootWeb 入门#
SpringBoot可帮助我们快速的构建应用程序,简化开发,提高效率。
略。
HTTP协议#
计算机网络课程中已有,此处快速略过。
概述 - 请求协议 - 响应协议 - 协议解析
特点:
- 基于TCP协议,面向连接、安全
- 基于请求-响应模型,一次请求对应一次响应
- 无状态协议,每次请求-响应都是独立的
HTTP状态码
- 1xx 响应中,临时状态码,ws中用得多
- 2xx 成功
- 3xx 重定向
- 4xx 客户端问题
- 5xx 服务器问题
Tomcat#
一个轻量级的web服务器,支持servlet、jsp等少量JavaEE规范。也被称为web容器/servlet容器。
起步依赖:把开发某功能常见的依赖聚合在了一起。例如springboot的父依赖。
D05 请求响应和分层解耦#
- HttpServletRequest 请求对象、HttpServletResponse 响应对象
- B-S架构 浏览器/服务器架构(维护方便 体验一般)、C-S架构 客户端/服务器架构模式(开发和维护麻烦 体验不错)
请求#
1 | |
- @RequestRaram中的required属性默认为true,表示该参数必须传递,否则将报错400。若为可选参数,可将required属性设置为false。
实体参数#
可将所有参数封装到实体类中。实体类中可再封装实体类,使用.区别。
1 | |
数组集合参数#
- 前端请求方式:使用两个相同的key。
- 后端接收方式:使用数组
String[] hobby/ 集合@RequestParam List<String> hobby(@RequestParam 这样才能将多个请求参数值封装到集合)
日期集合参数#
形参类似: @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime 服务端接收时需要指定前端传递的日期参数的格式。
JSON参数#
JSON数据键名与形参对象属性名相同,定义形参即可接收参数,需要使用 @RequestBody 标识。
路径参数#
参数作为URL的一部分。使用{...}来标识该路径参数,需要使用@PathVariable来获取路径参数。
1 | |
响应#
@ResponseBody
- 类型:方法注解、类注解
- 位置:Controller方法上/类上
- 作用:将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换为JSON格式响应
- @RestController = @Controller + @ResponseBody
可封装一个Result类统一响应的格式,便于项目的维护。
分层解耦#
单一职责原则:一个方法尽量只起到一个功能
三层架构#
- controller: 控制层,接收前端发送的请求,对数据进行处理,并响应数据
- service: 业务逻辑层,处理具体的业务逻辑
- dao: 数据访问层 Data Access Object,负责数据访问操作,包括数据的crud。
创建接口处理,将web接口分为三层。
_分层解耦#
- 内聚:软件中各个功能模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
- 软件设计原则:高内聚低耦合
使用容器类来封装特定实现类实现低耦合。
- 控制反转:IOC,对象的创建控制权由程序自身转移到外部(容器)。
- 依赖注入:DI,容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
- Bean对象:IOC容器中创建、管理的对象
IOC & DI 入门#
- 将Service层与Dao层的实现类交给IOC容器管理,在类上新增注解
@Component - 为Controller及Service注入运行时,依赖的对象,在成员变量上加上注解
@Autowired- 自动装配、简化开发、实现解耦 - 运行测试
- 需要修改调用的实现类时,更换
@Component的位置即可。
IOC详解#
将对象的控制权交给IOC容器,由容器来创建和管理这些对象。

- @RestController = @Controller + @ResponseBody
每一个Bean都有一个标识,在声明bean的时候可以通过注解当中的value属性来指定bean的名字。默认名字为类名(首字母小写)。指定方式 @Repository(value = "DaoA") / @Repository("DaoA"),一般不用指定。
使用以上四个注解都可以声明bean,但在springboot集成web开发中,只能使用@Controller。
声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。在创建时已经在启动类声明注解@SpringBootApplication中包含,默认扫描的范围是启动类所在包及其子包。
- 手动在新包中设置包扫描 @ComponentScan({“包名”, “原包名”}) // 不推荐。
- 按照SpringBoot项目规范,将包全部放在启动类所在包下。
DI详解#
@Autowired默认按照类型进行,如果存在多个相同类型的bean则会报错
解决方案:
@Primary: 在@Service之前设置bean的优先级@Qualifier("A"):在@Autowired上一行声明需要注入的是哪个bean@Resource(name = "empB"):在声明的上一行声明需要注入的是哪个bean(该注解是jdk提供的,是按照名称注入)
D06 MySQL、数据库设计、数据库操作#
本部分学习过,仅作补充记录。
- 关系型数据库:建立在关系模型基础上,由多张相互连接的二维表组成的数据库。
- 使用表存储数据,格式统一,便于维护
- 使用SQL语言操作,标准统一,使用方便,可用于复杂查询
- SQL:一门操作关系型数据库的编程语言,定义操作所有关系型数据库的统一标准。
部分标签#
- signed: 有符号范围(默认)
- unsigned: 无符号范围,只能存储正数,范围翻倍
double(5,2)长度位是5,小数位数是2,例如123.45- char节省性能,varchar节省空间
D07 MySQL 查询、多表操作#
- 起始索引=(页码-1)*每页记录数
- ECharts
case ... [when ... then ...] else ... end
物理外键#
- 影响增删改的效率
- 仅适用于单节点数据库
- 容易引发数据库的死锁问题
逻辑外键#
在业务中保证数据的完整性和一致性,而不在数据库中设置外键。
D08 MySQL 多表查询、事务、索引、Mybatis 入门#
多表查询#
- 标量子查询 </>/=
- 列子查询 in/not in
- 行子查询 =/<>/in/not in - 使用
(a,b)=(select a,b from xxx)实现 - 表子查询 from - 作为临时表使用
如果可以用连接查询替代子查询,尽量使用连接查询(效率更高)。
事务#
事务是一组操作的集合,是一个不可分割的工作单位,会把所有操作作为一个整体一起向系统提交/撤销操作请求,这些操作要么同时成功,要么同时失败。
- 在MySQL中,默认事务是自动提交的。
事务控制#
- 开启事务:start transaction; / begin;
- 提交事务:commit;
- 回滚事务:rollback;
四大特性#
- 原子性 A:事务是不可分割的最小操作单元
- 一致性 C:事务完成时,必须使所有数据都保持一致
- 隔离性 I:事务在不受外部并发操作影响的独立环境下运行
- 持久性 D:事务一旦提交或回滚,对数据库中的数据的改变是永久的
索引#
索引是帮助数据库高效获取数据的数据结构。
- 优点:提升查询效率,降低IO成本。/通过索引降低数据排序的成本,降低CPU消耗
- 缺点:占用存储空间,降低insert、update、delete的效率
使用的树#
MySQL的索引默认为B+树。
- 一个叶可以存储多个指针。每一个节点,可以存储多个key。
- 所有数据都在叶子节点保存,非叶子节点只用于存储数据。
- 叶子节点按从小到大顺序排序,形成双向链表。
语法#
- 创建索引
create [unique] index 索引名 on 表名(字段名); - 查看索引
show index from 表名 - 删除索引
drop index 索引名 on 表名
主键字段在建表时会自动创建,性能最高;添加唯一约束时,实则是添加了唯一索引。
Mybatis#
一款优秀的持久层框架,用于简化JDBC的开发。
Mybatis 入门#
步骤:准备工作、引入Mybatis依赖及配置(配置在application.properties中)、编写SQL语句
框架底层会自动生成实现类对象,并将该对象交给IOC容器管理。
数据库连接池:容器,负责分配、管理数据库连接。可以做到资源重用、提升系统响应速度、避免数据库连接遗漏。实现接口为DataSource。
不同连接池的区别:
- HikariCP为速度而生。它是一个追求极致性能、轻量、简洁的连接池,目标是做到最快、最高效、最低开销。
- Druid为监控和扩展而生。它不仅仅是一个连接池,更像一个数据库中间件,提供了强大、详尽的监控和丰富的扩展功能。
Lombok是实用的Java类库,能通过注解的形式自动生成各种方法,并可以自动化生成日志变量,简化Java开发、提高开发效率。

Mybatis 增删改查#
- 准备数据库表emp
- 创建一个新的springboot工程,选择引入起步依赖
- 在application.properties中引入数据库连接信息
- 创建对应实体类Emp
- 准备Mapper接口 EmpMapper
增删改操作可以为int返回值,返回本次操作影响的记录数。
删
1 | |
对表名、字段名进行动态设置时使用${id},但需要注意可能存在SQL注入。
增(接口方法)
1 | |
主键返回,需要在接口上添加注解@Options(keyProperty = "id", useGeneratedKeys = true)
改
1 | |
查
1 | |
条件查询
1 | |
可以使用concat字符串拼接函数,防止sql注入
1 | |
XML映射文件方式,规范:
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
- XML映射文件的namespace属性为Mapper接口全限定名一致
- XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致

MyBatisX插件 复杂语句建议使用XML,简单语句使用注解即可。
Mybatis 动态SQL#
随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。
<if> 标签用于判断条件是否成立。使用test属性进行条件判断,若条件为true,则添加SQL。

<where> 标签会自动判断里面的条件是否成立,并进行拼接/去除多余的and/or。

需求:动态更新员工信息,传递时有值才更新、没有传值不更新。
<set> 标签会自动在行首插入set关键字,并会删掉额外的逗号(在update语句中)
<foreach> 标签,循环遍历 SQL:delete from emp where id in (18,19,20)
public void deleteByIds(List<Integer> ids);

<sql> <include> 标签:配置在后期会存在代码复用性差的问题
1 | |
D10 综合案例(P74-85)#
Restful 表述性状态转换,通过请求方式的区分来定义接口功能的不同。
- REST是风格,不是规定,可以打破
- 描述功能模块通常使用复数形式,表示此类资源
一个完整的请求路径,应该为类上的 @RequestMapping 的value属性 + 方法上的 @RequestMapping 的value属性
日志技术#
- JUL:JavaSE平台提供的官方日志框架,配置相对简单、不够灵活、性能较差
- Log4j:流行的日志框架,提供了灵活的配置选项,支持多种输出目标
- Logback:基于Log4j升级而来,提供了更多的功能和配置选项,性能更佳
- (规范)Slf4j:简单日志门面,提供了一套日志操作的标准接口及抽象类,允许应用程序使用不同的底层日志框架
日志级别#

D11 综合案例-多表关系(重复) & 员工管理(P86-100)#
PageHelper是第三方提供的在Mybatis框架中用来实现分页的插件,用来简化分页操作、提高开发效率。
- PageHelper语句结尾不能加分号
- PageHelper仅对设置分页操作的下一次查询生效
在插入数据后获取主键 @Options(useGeneratedKeys = true, keyProperty = "id")
D12 事务管理 & 文件上传(P101-109)#
注解:@Transactional 使用于业务层的方法、类、接口上 - 将当前方法交给spring进行事务管理。推荐加在一个多次进行增删改的接口上。
rollbackFor - 出现何种异常要进行事务的回滚 eg. @Transactional(rollbackFor = {Exception.class})。默认出现运行时异常才会回滚。s
事务传播行为:当一个事务被另一个事务方法调用时,应当如何进行事务控制。

参数配置化,通过 @Value("${aliyun.oss.endpoint}$") 注解引入。也可批量注入(需要注入的属性较多时更方便),封装到实体类中:@Data @Component @ConfigurationProperties(prefix = "aliyun.oss")。
D13 删除员工 & 修改员工 & 异常处理(P110-118)#
Mybatis中封装查询结果时,若查询返回的字段名与实体的属性名可以对应,用resultType,否则用resultMap手动封装。
定义全局异常处理器: @RestControllerAdvice = @ControllerAdvice + @ResponseBody 及 @ExceptionHandler
D14 实战问题记录(P119)#
- Q:无法自动装配。找不到 ‘StudentService’ 类型的 Bean。
- A:实现类没有继承 StudentService 导致找不到实现的Service。
- Q:创建mapper时错误声明了其为类,需要重新声明为接口?
- A:删除重建 / 将class修改为interface,同时修正方法体。
- Q:部门下是否存在员工的判定?
- A:Autowired导入一个EmpMapper类,对类单独写一个实现方法 select count(*)。
- Mapper层从数据库表映射到实体类Dept,最终结果放置在
List<Dept>中。 - Service层创建一个专门用于数据传输的类DTO(Data Transfer Object),接收到对象并将Dept的信息映射到DTO_Dept中。
- Controller层在
@RestController注解的情况下会字段进行序列化,形成json。
ECharts处理#
Mapper:查询出包含班级名、人数的列表。#
Mapper 接口
1 | |
Mapper XML
1 | |
从而获得类似于
1 | |
的数据结构。
Service:接收原始列表,根据业务需求重组数据,将其拆分成两个列表并放在某个容器中。#
实现类
1 | |
Controller:Spring自动序列化。#
1 | |
最终的映射结果:
1 | |
D15 登录(P120-132)#
登录接口查数据库表 where username = xxx and password = xxx。
- 登录标记:用户登录成功后,在后续每次请求中都可以获取到该标记(会话技术)
- 统一拦截:过滤器Filter、拦截器Interceptor
会话技术#
- 会话:用户打开浏览器,访问web服务器的资源,会话建立 - 有一方断开连接,会话结束。
- 会话跟踪:服务器需要识别多次请求是否来自同一浏览器,以便在同一会话的多次请求之间共享数据。
- 客户端会话跟踪技术:Cookie / 服务端会话跟踪技术:Session / 令牌技术:JWT
#
Cookie是HTTP协议所支持的技术。响应头 Set-Cookie;请求头 Cookie
- 移动端APP无法直接使用。
- 不安全,用户可以自己禁用cookie。
- Cookie不能跨域。
#
Cookie - JSESSIONID
声明HttpSession session,存值session.setAttribute(),取值session.getAttribute()
- 数据存储在服务端,安全。
- 服务器集群环境下无法直接使用Session
- 有Cookie的所有缺点。
令牌#
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器存储压力
- 但需要自己实现
JWT令牌#
登录成功后生成令牌,统一拦截校验。
- 第一部分:Header,记录令牌类型、签名算法
- 第二部分:Payload,携带一些自定义信息、默认信息
- 第三部分:Signature,防止Token被篡改、确保安全性
使用
- 引入jjwt的依赖。
- 调用官方提供的工具类Jwts来生成或解析jwt令牌。
生成令牌
1 | |
解析令牌
1 | |
令牌失效或被篡改,在解析时会报错。
过滤器Filter#
过滤器可以把对资源的请求拦截下来,从而实现特殊的功能。可以完成一些通用的操作,包括登录校验、统一编码处理、敏感字符处理等。
定义一个类实现Filter接口(init doFilter destroy)、@WebFilter(urlPatterns="/*") 、 @ServletComponentScan
在Filter过程中验证是否为登录请求、验证是否携带token、验证token是否有效。
过滤器链:在一个web应用中可以配置多个过滤器。优先级默认按照类名(字符串)的自然排序。
拦截器Interceptor(Spring)#
拦截器是一种动态拦截方法调用的机制,类似于过滤器,主要用来动态拦截控制器方法的执行。
- 定义:实现HandlerInterceptor接口的preHandle、postHandle、afterCompletion方法;
- 配置:定义一个配置类实现WebMvcConfigurer接口,注册拦截器(
/**)
区别:拦截路径需要用.addPathPatterns("/**") 增加拦截路径、.excludePathPatterns("/login") 排除拦截路径。/* 拦截一级路径、 /** 任意级路径
过滤器和拦截器的区别#
- 接口规范不同:过滤器需要实现Filter接口,拦截器需要实现HandlerInterceptor接口
- 拦截范围不同:过滤器会拦截所有的资源(所有的HTTP请求)、Web容器层面,拦截器只会拦截Spring环境中的资源(访问Controller的请求)、依赖于Spring容器
D16 SpringAOP(P133-140)#
AOP - 面向切面编程
1 | |
- 优点:减少重复代码、代码无侵入、提高开发效率、维护方便。
- 开发步骤:引入AOP依赖、编写AOP程序
- 应用场景:记录系统操作日志、事务管理、权限控制…
核心概念#
- 连接点:JoinPoint,可以被AOP控制的方法
- 通知:Advice,指共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用 - 实际被AOP控制的方法
- 切面:Aspect,描述通知与切入点的对应关系
- 目标对象:Target,通知所应用的对象
执行流程#
创建代理对象,为目标对象实现同一个接口,使用通知方法中的逻辑。
注释的类型#
- @Around:在目标方法前后均执行 -> 需要自己调用方法让原始方法执行,返回值必须指定为Object
- @Before:在目标方法前执行
- @After:在目标方法后执行,是否有异常都执行
- @AfterReturning:在目标方法后执行,有异常时不会执行
- @AfterThrowing:在目标方法发生异常后执行
@Pointcut:公共的切入点表达式
1 | |
通知顺序#
当有多个切面的切入点都匹配到了目标方法,目标方法运行时多个通知方法都会被执行。
顺序:不同切面类中,默认按照切面类的类名字母排序。或者可以用@Order(数字)控制顺序,数字越小越先执行。
切入点表达式#
execution(...) 基于方法的签名来匹配#
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
- 访问修饰符:可省略(public、protected)
- 包名.类名:可省略 – 不建议省略
- throws 异常:可省略(是方法上声明抛出的异常,不是实际抛出的异常)
*可以通配任意一个参数或一部分..多个连续的任意符号,可以通配任意层级的包、或任意类型任意个数的参数- 支持逻辑运算符,与/或多个execution
书写建议
- 方法名在命名时尽量规范,方便切入点表达式快速匹配
- 描述切入点方法通常基于接口描述,增强扩展性
- 尽量缩小切入点的匹配范围,防止效率降低
@annotation(...) 根据注解匹配#
- 定义注解anno,在注解方法上新增注解
@Target(Element.METHOD)及@Retention(RetentionPolicy.RUNTIME)
连接点#
ProceedingJoinPoint(仅对于@Around通知) 或 JoinPoint 类型,可以获得方法时的执行信息。
getTarget()获取目标对象getTarget().getClass().getName()获取目标类getSignature().getName()获取目标方法getArgs()获取目标方法参数
ThreadLocal#
ThreadLocal实为线程的局部变量,为每个线程提供一份单独的存储空间,具有线程隔离的效果、不同的线程之间不会相互干扰。
public void set(T value)设置当前线程的线程局部变量的值public T get()返回当前线程所对应的线程局部变量的值public void remove()移除当前线程的线程局部变量
操作步骤
- 定义ThreadLocal操作的工具类
- 在TokenFilter中解析当前登录的ID,存入ThreadLocal
CurrentHolader.setCurrentId(empId) - 从线程中获取ID
CurrentHolder.getCurrentId() - 在AOP程序中获取当前员工ID,删除
CurrentHolder.remove()
D17 SpringBoot原理&Maven高级(P141-151)#
配置文件的优先级#
以下配置文件优先级由大到小,但推荐统一使用一种。
- 命令行参数
- Java系统属性
- application.properties
- application.yml(主流)
- application.yaml
启动时还可以通过Java系统属性或命令行参数进行属性配置,优先级更高。
Bean作用域#
bean作用域共有以下五种,后三种在web环境才生效。
- singleton 容器内同名称的bean只有一个实例
- prototype 每次使用该bean时创建新的实例
- request 请求范围内创建新的实例
- session 会话范围内创建新的实例
- application 应用范围内创建新的实例
可以添加 @Scope("xxx") 设置bean的作用域。在单例中 @Lazy 表示延迟初始化,延迟到第一次使用时再创建这个bean。
实际开发中,绝大部分的bean都会是单例的。可以节约资源、提升性能。无状态的bean即是线程安全的,有状态的bean在单例时 多线程同时操作时为线程不安全。
第三方Bean#
- 如果要管理的bean对象来自第三坊,需要在启动类中使用
@Bean注解。通过bean注解的name或value属性可以声明bean的名称,若不声明、默认为方法名。 - 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类。
自动配置#
自动配置:Spring项目启动后,一些配置类、bean对象自动存入到IOC容器中,不需要手动去声明,从而简化开发、省略配置。
通过@ComponentScan注解扫描指定的包。 /
在启动类中用@Import 注解导入的类(可以直接导入普通类,无需在类上添加@Component等注解)会被Spring加载到IOC容器中。
导入ImportSelector接口的实现类可以实现批量导入类。
还可将import注解再封装到一个注解当中,这样就能通过注解@Enablexxx批量导入。(更方便)
自动配置-@Conditional#
自动配置 @Conditional 按照一定的条件进行判断,在满足给定条件后才会注册对于的bean对象到Spring IOC容器中。
@ConditionalOnClass:判断环境中是否有对应的字节码文件,才注册@ConditionalOnMissingBean:判断环境中没有对应的bean,才注册@ConditionalOnProperty:判断配置文件中有对应属性和值,才注册
自定义starter#
在实际开发中经常会定义一些公共组件提供给各个项目团队使用,可以将这些组件封装为SpringBoot的start。
Maven高级#
分模块设计:将一个大项目拆分为若干个子模块,方便项目的管理、维护、扩展。
拆分策略
- 按照功能模块拆分
- 按层拆分
- 按照功能模块 + 层拆分
先针对模块功能进行设计,再进行编码。
继承#
子工程可以继承父工程中的配置信息,常见于依赖关系的继承。可以简化依赖配置、统一管理依赖。 使用标签:<parent>。不支持多继承,但支持多重继承。
- jar:普通模块打包,springboot项目基本都是jar包
- war:普通web程序打包,需要在外部的tomcat服务器运行
- pom:父工程或聚合工程,不写代码,仅进行依赖管理
- 在子工程中配置继承关系后,坐标中的groupId可以省略、会自动继承父工程
- relativaPath指定父工程的pom文件的相对位置,若不指定,会自动从本地仓库/远程仓库查找
版本锁定#
如果不是所有项目都需要用的依赖,不太建议在父工程引入。在maven中,可以在父工程的pom文件中通过 <dependencyManagement> 来统一管理依赖版本。
自定义属性可以在 <properties> 标签中定义<lombok.version>1.18.34</lombok.version>,在版本中用 ${lombok.version} 引用即可。
聚合#
将多个模块组织成一个整体,同时进行项目的构建。
- 首先需要有一个聚合工程,有且仅有一个pom文件(可以与父工程同一个)。
- maven中可以通过
<modules>设置当前聚合工程所包含的子模块名称。
继承和聚合#
- 继承与聚合都属于设计型模块,打包方式都为pom,常设计到同一个pom文件中。
- 继承用于简化依赖配置、统一管理依赖版本
- 聚合用于快速构建项目,在父工程中配置聚合的模块
私服#
私服是一种特殊的远程仓库,架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。
项目版本:RELEASE/SNAPSHOT
- 设置私服的访问用户名/密码 - settings.xml中的servers中配置
- IDEA的maven工程的pom文件中配置上传地址

- 设置私服依赖下载的仓库组地址(快照默认不可使用)

后端总结(P152)#
Controller(接收请求) - Service(逻辑处理) - Dao(数据访问、操作数据库) - MySQL
过滤器、拦截器 - 拦截前端发起的请求
IOC/DI/AOP/事务管理/全局异常处理/Cookie.Session/JWT/阿里云OSS/Mybatis
D18 Vue + ElementPlus(P152-159)#
<script setup>预处理<style scoped>设置样式的作用域范围
1 | |
Element 引入中文语言#
1 | |
D20 Tlias案例(P160-166)#
可以在vite.config.js中配置前端请求服务器信息。

D21 Tlias案例(P167-174)#
watch函数:侦听一个或多个响应式数据源,并在数据源变化时调用传入的回调函数。
- 导入watch函数
- 执行watch函数,传入要侦听的响应式数据源喝回调函数
{deep: true}深度侦听,侦听对象的全部属性{immediate: true}在 代码创建时立即侦听- 亦可以侦听对象的单个属性
user->() => user.value.age
动态绑定:<el-option v-for="j in jobs" :key="j.value" :label="j.name" :value="j.value"></el-option>
在import时可以为函数取别名 import {xxx as aaa} from 'xxx'
D21 Tlias案例(P175-181)#
- Ajax请求头中携带令牌 - 通过request拦截器完成
- 收到401响应跳转到登录页面 - 通过response拦截器完成
- 使用nginx反向代理进行路径重写(rewrite / proxy_pass)
D22 项目部署-Linux(P182-190)#
ls -l <dir>=ll <dir>:显示指定目录下内容head [-n] fileName:输出文件开头的n行内容tail [-n] fileName输出文件末尾的n行内容