JavaWeb
什么是web?
web:全球广域网,也称万维网(world wide web)/
web网站工作流程
web开发学习内容
一、前端技术
初识web前端
- 网页由哪些部分组成?
- 文字、视频、音频、图片、表格、超链接…
- 网页背后的本质是什么?
- 编写的前端代码
- 前端代码如何转换成用户眼中的网页?
- 通过浏览器渲染和解析形成用户看到的网页
- 浏览器对代码进行解析渲染的部分称为浏览器内核
web标准
- web标准也被称为网页标准,由一系列标准组成,大部分由W3C(world wide web consortium,万维网联盟)负责指定。
- 三个组成部分
- HTML:负责网页的结构(页面元素和内容)
- CSS:负责网页的表现(页面元素的外观、位置等页面样式)
- Javascript:负责网页的行为(交互效果)
1 HTML、CSS、JS
1.1 HTML
什么是HTML?
HTML(HyperText Markup Language):超文本标记语言。
- 超文本:超越了文本的限制,比普通文本更加强大。除了文字信息,还可以定义图片、音频、视频等内容。
- 标记语言:由标签构成的语言。
- HTML标签都是预定义好的。例如
<a>
表示展示超链接,<img>
展示图片,<video>
展示视频。 - HTML代码直接在浏览器中运行,HTML标签由浏览器解析。
- HTML标签都是预定义好的。例如
HTML快速入门
- 新建文本文件,后缀名改为.html
- 编写HTML结构标签
- 在
<body>
中填写内容
|
|
特点:
- HTML标签不区分大小写
- HTML标签属性值单双引号都可以
- HTML语法松散
基础标签&样式
以新浪新闻为例
- 新浪新闻-标题
- 标题排版
- 标题样式
- 超链接
- 新浪新闻-正文
|
|
两个常见布局标签
- 布局标签:在实际开发网页中,会大量频繁的使用div和span这两个没有语义的布局标签。
<div> <span>
- 特点
- div标签
- 一行只显示一个(独占一行)
- 宽度默认是父元素的宽度,高度默认由内容撑开
- 可以设置宽高
- span标签
- 一行可以显示多个
- 宽度和高度默认由内容撑开
- 不可以设置宽高
- div标签
|
|
表格标签
标签 | 描述 | 属性 |
---|---|---|
<table> |
定义表格整体,可以包裹多个<tr> |
border:规定表格边框宽度 width:规定表格的宽度 cellspacing:规定单元之间的空 间 |
<tr> |
表格的行,可以包裹多个<td> |
|
<td> |
表格单元格,包裹内容 | 如果是表头单元格,可以替换为<th> |
表单标签
标签:<form>
表单项:不同类型的input元素,下拉列表,文本域等。
<input>
:定义表单项,通过type属性控制输入形式。
<select>
:定义下拉列表<textarea>
:定义文本域
表单属性
- action:规定当前提交表单时向何处发送表单数据,url。
- method:规定用于发送表单数据的方式。get、post
|
|
1.2 CSS
什么是CSS?
CSS(Cascading Style Sheet):层叠样式表,用于控制页面的样式(表现)。
CSS引入方式
- 行内样式:写在标签的style属性中(不推荐)
<h1 style = "xxx:xxx ; xxx:xxx;">中国新闻网</h1>
- 内嵌样式:写在style标签中(可以写在页面任何位置,但通常约定写在head标签中)
|
|
- 外联样式:写在一个单独的.css文件中(需要通过link标签在网页中引入)
|
|
css选择器
- 元素选择器 根据标签名选择
- id选择器 #id属性值 id不能重复
- 类选择器 .class属性值 class可以重复
指定范围越小,选择器级别越高。
CSS盒子模型
- 盒子:页面中所有元素(标签),都可以看作一个盒子,由盒子将页面中的元素包含在一个矩形区域内,通过盒子的视角更方便的进行页面布局。
- 盒子模型组成:内容区域(content)、页面布局(padding)、边框区域(border)、外边距区域(margin)
padding为填充物,border为边界,margin不属于盒子。
1.3 JavaScript
什么是JavaScript?
- JavaScript简称js,是一门跨平台,面向对象的脚本语言。主要用来控制网页行为,他使网页可交互。
- Java与JavaScript是完全不同的语言,但基础语法相似。
- JavaScript在1995年由Brendan Eich发明,并于1997年称为ECMA标准。
- ECMAScript 6(ES 6)是最新的JavaScript版本(发布于2015年)。
js引入方式
- 内部脚本:将JS代码定义在html界面中
- JavaScript代码必须位于
<script> </script>
标签之间 - 在html文档中,可以在任意地方防止任意数量的
<script>
- 一般会把脚本置于
<body>
元素的底部,可以改善显示速度
- JavaScript代码必须位于
- 外部脚本:将js代码定义在外部js文件中,然后引入到html页面中
- 外部js文件中,只包含js代码,不包含
<script>
标签 <script>
标签不能自闭合
- 外部js文件中,只包含js代码,不包含
js基础语法
-
书写语法
-
区分大小写:和java一样,变量名函数名以及其他一切都是区分大小写的
-
每行结尾的分号可有可无
-
注释:
-
单行注释://
-
多行注释:/* */
-
-
大括号表示代码块
-
-
输出语句
- 使用windows.alert()写入警告框
- 使用document.write()写入html输出
- 使用console.log()写入浏览器控制台
-
变量
- 使用var关键字声明变量,var定义的变量是全局变量,可以重复定义
- ECMAscript6新增let关键字,不允许重复声明,在let代码块内生效
- ECMAscript6新增constant关键字,用来声明一个只读的常量,一旦声明,常量的值不能改变。
- JavaScript是一门弱类型语言,变量可以存放不同类型的值
- 变量名需要如下规则
- 组成字符可以是任何字母,数字,下划线或者美元符
- 数字不能开头
- 建议使用驼峰命名
- 使用var关键字声明变量,var定义的变量是全局变量,可以重复定义
-
数据类型
- JavaScript数据类型分为原始类型和引用类型,使用typeof运算符可以获取数据类型
- 原始类型
- number 数字小数NaN
- string 单引号或者双引号
- boolean
- null 对象为空
- undefined 变量未初始化时默认是undefined
- 原始类型
- JavaScript数据类型分为原始类型和引用类型,使用typeof运算符可以获取数据类型
-
运算符
- 算数 + - * / ++ –
- 逻辑
- 比较
==
会进行类型转换,===
不会类型转换- 类型转换
- 字符串转数字:字面值转数字,不是数字返回NaN
- 其他类型转boolean 0,NaN 空字符串,null 和 underfined转为false
- 类型转换
- 赋值
- 三元
-
流程控制语句
- if..else
- switch
- for
- while
- do..while
js函数
- 介绍:函数是被设置为执行特定任务的代码块。
- 定义:JavaScript通过function关键字进行定义,语法为
|
|
- 注意:
- 形参不需要定义类型,因为JavaScript是弱类型语言
- 返回值也不需要定义类型,可以在函数内部直接return返回即可
- 调用:函数名称(实参列表)
- 函数第二种定义方式
|
|
js对象
-
Array
var array = new array(1,2,3,4) 或者 var array = [1,2,3,4]
- 访问:
arr[索引值]
- 特点:变长数组,类型可变
- 属性:length
- 方法:forEach(),push(),splice()
-
String
var 变量名 = new String("xxx") var 变量 = “"
- 属性:length
- 方法:charAt() indexOf() trim() substring()
-
JSON JavaScript Object Notation
var 变量名 = '{"key":value1,"key2":value2}';
- json字符串转JS对象:
var jsObject = JSON.parse(userstr)
- js对象转JSON字符串:
var jsonstr = json.stringify(jsObject)
-
BOM,Brower Object Model,浏览器对象,允许JavaScript与浏览器对象,JavaScript将浏览器各个组成部分封装为对象
- window 浏览器窗口
- Navigator 浏览器对象
- Screen 屏幕
- History 历史记录
- Location 地址栏
-
DOM,Document Object Mode,文档对象,将标记语言的各个组成部分封装为对应的对象
- Document 整个文档对象
- Element 元素对象
- Attribute 属性对象
- Text 文本对象
- Comment 注释对象
js事件监听
事件:HTLM事件是发生在HTML上的事情。比如按钮被点击,鼠标移动到元素上,按下键盘按键。
事件监听:JavaScript可以在事件被侦测到时执行代码。
事件绑定:
- 通过HTML标签中的事件属性进行绑定
- 通过dom元素进行绑定
2 Vue、ElementUI、Nginx
2.1 vue
什么是vue?
- vue是一套前端框架,免除原生JavaScript的DOM操作,简化书写。
- 基于MVVM(model-view-viewmodel)思想,实现数据的双向绑定,将编程的关注点放在数据上。
|
|
Vue常用指令
- 指令:HTML标签上带有v-前缀的特殊属性,不同指令具有不同的含义。例如v-if,v-for
- 常见指令:v-bind v-model v-on v-if v-for等等
v-bind
v-bind:为HTML标签绑定属性值,如设置href、css样式等
|
|
v-model
v-model:在表单上创建双向元素绑定
|
|
v-on
v-on:为HTML标签绑定事件
|
|
v-if
v-if、v-else-if、v-else:条件性的渲染某元素,判定为true时渲染,否则不渲染
|
|
v-show
v-show:根据条件展示某元素,区别在于切换的是display属性的值
|
|
v-for
v-for:列表渲染,遍历容易的元素或者对象的属性
|
|
Vue生命周期
- 生命周期:指一个对象从创建到销毁的整个过程
- 生命周期的八个阶段,每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)
- mounted:挂载完成,vue初始化成功,HTML页面渲染成功。(发送到i服务端,加载数据)
什么是Element?
- Element:是饿了么团队研发的,一套为开发者、设计师和产品经理准备的基于Vue 2.0的桌面端组件库。
- 组件:组成网页的部件,例如超链接,按钮,图片,表格,表单,分页条等等。
快速入门
- 安装ElementUI组件库(在当前工程的目录下),命令行执行指令。
npm install element-ui@2.15.3
- 引入ElementUI组件库
|
|
- 访问官网,复制组件代码,调整
3 Ajax、Axios
3.1 Ajax
什么是Ajax?
- 概念:Asynchronous JavaScript And XML,异步的JavaScript和XML
- 作用:
- 数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据
- 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:联想搜索,用户名是否可用的校验等等。
3.2 Axios
什么是Axios?
- 介绍:Axios对原生的Ajax进行了封装,简化书写,快速开发
Axios使用方式
- 引入Axios的js文件
<script src="js/axios-0.18.0.js"></script>
- 使用Axios发送请求,并获取相应结果
|
|
Axios请求方式别名
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.post(url[,data[,config]])
- axios.put(url[,data[,config]])
|
|
4 前端工程化
4.1 前后端分离开发
什么是前后端分离开发?
YAPI
YAPI:是高校、易用、功能强大的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务
4.2 前端工程化
环境准备
vue-cli:vue官方提供的一个脚手架,用户快速生成一个vue的项目模板
vue-cli提供了以下功能:
- 统一的目录结构
- 本地部署
- 热部署
- 单元测试
- 集成打包上线
依赖环境:NodeJS
Vue项目
- 创建
- 命令行:
vue create vue-project01
- 图形化界面
- 命令行:
- 目录结构
- node_modules 整个项目的依赖包
- public 存放项目的静态文件
- src 存放项目的源代码
- assets 静态资源
- components 可重用的组件
- router 路由配置
- views 视图组件
- app.vue 入口页面
- main.js 入口js文件
- package.json 模块基本信息,项目开发所需模块,版本信息
- vue.config.js 保存vue配置的文件,如代理,窗口的配置等
Vue项目开发流程
默认首页:index.html,默认引入main.js
入口文件:main.js,引入公共组件
vue的组件以.vue结尾,每个组件由三个部分组成:<template><script><style>
template是模板部分,由它生成html代码。script中用来控制模板的数据来源和行为。style是CSS样式。
vue路由
前端路由:URL中的hash(#号)与组件之间的对应关系。
vue router是Vue的官方路由。
组成:
- VueRouter:路由器类,根据路由请求在路由视图中动态渲染选中的组件。
<router-link>
:请求链接组件,浏览器会渲染成<a>
<router-view>
:动态视图组件,用来渲染展示与路由器路径对应的组件。
使用流程:
- 安装(创建Vue项目时已选择)
npm install vue-router@3.5.1
- 定义路由表,在index.js下定义
|
|
打包
前端build后出现dist目录,将dsit中文件部署在nginx服务器上。
nginx
nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件代理服务器。特点是占用内存少,并发能力强,在大型互联网公司都有非常广泛的使用。
目录内容:
- conf 配置文件目录
- contrib
- docs
- html 静态资源目录
- logs 日志文件目录
- temp 临时文件目录
- nginx.exe
nginx默认占用80端口号,如果80端口号呗占用,可以在nginx.conf中修改端口号。(netstat -ano|findStr 80)
二、Web后端
1 Maven
1.1 概述
什么是Maven?
Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具。
Maven基于项目对象模型(POM,project object model)的概念,通过一小段描述信息来管理项目的构建。
仓库:用于存储资源,管理各种jar包。
- 本地仓库:自己计算机上的一个目录
- 中央仓库:由Maven团队维护的全球统一的。仓库地址链接
- 远程仓库(私服):一般由公司团队搭建的私有仓库
Maven的作用
-
依赖管理 方便快捷的管理项目依赖的资源(jar包),避免版本冲突的问题
-
统一项目结构 提供标准,统一的项目结构
- maven-project
-
src
-
main 实际项目资源
- java java源代码目录
- resources 配置文件目录
-
test 测试项目资源
- java
- resources
-
-
pom_xml 项目配置文件
-
- maven-project
-
项目构建 标准跨平台(Linux,Windows,MacOS)的自动化项目构建方式
1.2 IDEA集成Maven
- 配置Maven环境
- 修改Maven本地仓库地址
- 修改Runner中JDK版本
- 修改编译器中字节码版本
- 创建Maven项目
- 创建模块,选择maven,点击next
- 填写模块名称,坐标信息,点击finish,创建完成
- 编写HelloWorld,并运行
- 导入Maven项目
- maven面板点击+号选择pom.xml
- projectstructure modules import
maven坐标
什么是坐标?
- Maven中坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置。
- 使用坐标来定义项目或引入项目中需要的依赖。
坐标的主要组成
- groupId:通过当前Maven项目隶属组织名称
- artifactId:定义当前的Maven项目名称
- version:定义当前项目版本号
1.3 依赖管理
依赖配置
- 依赖:指当前项目运行所需要的jar包,一个项目可以引入多个依赖。
- 配置:
- 在pox.xml中编写
<dependencies>
标签 - 在
<dependencies>
标签中使用<dependency>
引入坐标 - 定义坐标的groupId,artifactId,version
- 点击刷新按钮,引入最新加入的坐标
注意:第一次使用依赖可以从链接中检索依赖坐标。
依赖传递
依赖具有传递性。
- 直接依赖:当前项目直接通过依赖配置建立的依赖关系。
- 间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源。
排除依赖:指主动断开依赖的资源,被排除的资源无需指定版本。
依赖范围
依赖的jar包,默认情况下,可以在任何地方使用。可以通过<scope>...</scope>
设置其作用范围。
作用范围:
- 主程序范围有效。(main文件夹范围内)
- 测试程序范围有效。(test文件夹范围内)
- 是否参与打包运行。(package指令范围内)
scope取值 | 主程序 | 测试程序 | 打包(运行) | 示例 |
---|---|---|---|---|
compile(默认) | Y | Y | Y | log4j |
test | - | Y | - | junit |
provided | Y | Y | - | servlet-api |
runtime | - | Y | Y | jdbc驱动 |
生命周期
maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一。
maven中有3套相互独立的生命周期:
- clean:清理工作。
- default:核心工作,如:编译,测试,打包,安装,部署等
- site:生成报告、发布站点等
每套生命周期包含一些阶段(phase),阶段是由顺序的,后面的阶段依赖于前面的阶段。
- clean:移除上一次构建生成的文件
- compile:编译项目源代码
- test:使用合适的单元测试框架运行测试
- package:将编译后的文件打包,如jar、war
- install:安装项目到本地仓库
2 SpringBootWeb
2.1 Spring
Spring概述
spring发展到今天已经称为一种开发生态圈,Spring提供了若干个子项目,每个项目用于完成特定的功能。
SpringBoot
SpringBoot可以帮助我们快速的构建应用程序,简化开发、提高效率。
2.2 SpringBootWeb入门
SpringBootWeb快速入门
案例需求:使用SpringBoot开发一个web应用,浏览器发起/hello后,给浏览器返回字符串"Hello World!"
步骤:
-
创建Springboot工程,并勾选web开发相关依赖。
-
定义HelloController类,添加方法hello,并添加注解。
-
1 2 3 4 5 6 7 8 9 10 11 12 13
package com.learning.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; //请求处理类 @RestController public class HelloController { @RequestMapping("/hello") public String hello() { System.out.println("Hello World~"); return "Hello World~"; } }
-
-
运行测试。
2.3 HTTP协议
HTTP-概述
- 概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器与服务器之间数据传输的规则。
- 特点:
- 基于TCP协议:面向连接,安全。
- 基于请求-响应模型:一次请求对应一次响应。
- HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
- 缺点:多次请求之间不能共享数据。
- 优点:速度快。
HTTP-请求协议
HTTP-响应协议
状态码分类 | 说明 |
---|---|
1xx | 响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它 |
2xx | 成功——表示请求已经被成功接收,处理已完成 |
3xx | 重定向——重定向到其它地方:它让客户端再发起一个请求以完成整个处理。 |
4xx | 客户端错误——处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 |
5xx | 服务器端错误——处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等 |
状态码 | 英文描述 | 解释 |
---|---|---|
==200== | OK |
客户端请求成功,即处理成功,这是我们最想看到的状态码 |
302 | Found |
指示所请求的资源已移动到由Location 响应头给定的 URL,浏览器会自动重新访问到这个页面 |
304 | Not Modified |
告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向 |
400 | Bad Request |
客户端请求有语法错误,不能被服务器所理解 |
403 | Forbidden |
服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源 |
==404== | Not Found |
请求资源不存在,一般是URL输入有误,或者网站资源被删除了 |
405 | Method Not Allowed |
请求方式有误,比如应该用GET请求方式的资源,用了POST |
428 | Precondition Required |
服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头 |
429 | Too Many Requests |
指示用户在给定时间内发送了太多请求(“限速”),配合 Retry-After(多长时间后可以请求)响应头一起使用 |
431 | Request Header Fields Too Large |
请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。 |
==500== | Internal Server Error |
服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧 |
503 | Service Unavailable |
服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好 |
HTTP-协议解析
通过网络编程可以完成浏览器发送的http请求,并且根据http协议填充响应体发送给浏览器。但这一过程过于繁琐,纯粹的字符串操作,且解析过于复杂。所以采用web服务器软件完成协议解析工作。
2.4 Web服务器-Tomcat
web服务器
web服务器是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。主要功能是"提供网上信息浏览服务"。
Tomcat简介
- 概念:Tomcat是Apache软件基金会一个核心项目,是一个开源免费的轻量级Web服务器。支持Serlet/JSP少量JavaEE规范。
- JavaEE:java Enterprise Edition,Java企业版。
- Tomcat也被称为Web容器,Servlet容器。Servelet程序需要依赖于Tomcat才能运行。
Tomcat基本使用
SpringBoot内嵌Tomcat,当启动类运行时,会自动启动内嵌的tomcat服务器。
3 SpringMVC基础
3.1 SpringMVC
M代表: Model模型
V代表: View视图
C代表: Control控制层
用来进行分层的结构,这样代码分离结构清晰,各层代码,各司其职,易于开发大型项目。
MVC(Model模型、View视图、Control控制层),将软件进行分层达到松耦合的效果。
通用的软件编程思想, 在MVC设计模式中认为, 任何软件都可以分三层:控制层(Controller)、数据处理模型(Model)、负责展示数据的视图(View)。
在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面这三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分。如果某一个模块发生变化,应该尽量做到不影响其他两个模块。提高代码的可读性,实现程序间的松耦合、提高代码复用性。
3.2 请求响应
请求响应概述
请求
Postman
Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。常用于接口测试。
简单参数
- 原始方式:原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取。
- SpringBoot方式
- 简单参数:参数名和形参名相同,定义形参即可接收参数。
- 如果方法形参名称与请求参数不匹配,可以使用@RequestParam完成映射。该注解的required属性默认是true,代表请求参数必须传递。
实体参数
- 简单实体对象:请求参数名与形参对象属性名相同,定义POJO接收即可。
- 复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。
数组集合参数
- 数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参可接收参数。
- 集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系。
日期参数
- 日期参数:使用@DateTimeFormat 注解完成日期参数格式转换。
Json参数
- Json参数:Json数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody 标识。
路径参数
- 路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用@PathVariable 获取路径参数。
响应
@ResponseBody
- 类型:方法注解、类注解
- 位置:controller方法上/类上
- 作用:将方法的返回值直接响应,如果返回值类型是实体对象/集合,将会转换为json格式响应
- 说明:@RestController = @Controller + @ResponseBody
统一响应结果
|
|
3.3 分层解耦
三层架构
- Controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
- service:业务逻辑层,处理具体的业务逻辑。
- dao:数据访问层(data access object)(持久层),负责数据访问操作,包括数据的增、删、改、查。
分层解耦
- 内聚:软件中各个模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联程度。
- 软件设计原则:高内聚低耦合
IOC&DI入门
步骤:
- Service层及Dao层的实现类,交给IOC容器管理,加上注解**@component**
- 为controller及service注入运行时,依赖的对象。加上注解**@Autowired**
- 运行测试
IOC详解
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:
注解 | 说明 | 位置 |
---|---|---|
@Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
@Controller | @Component的衍生注解 | 标注在控制器类上 |
@Service | @Component的衍生注解 | 标注在业务类上 |
@Repository | @Component的衍生注解 | 标注在数据访问类上(由于mybatis整合,用的少) |
注意事项
- 在声明Bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明bean,但是在springboot集成web开发时,声明控制器bean只能用@Controller
Bean组件扫描:
- 前面声明的bean四大类,要想生效,还需要被组件扫描注解@ComponentScan扫描。
- @ComponentScan注解虽然没有显示配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。
DI详解
bean注入:
- @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会出现报错。
解决方案:
- @Primary 设置优先级。置于@Service上方
- @Qualifier 配合@Autowired下方,指定使用哪一个bean。@Autowired + @Qualifier(“bean名字”)
- @Resource 此时不需要@Autowired注解,直接指定bean。@Resource(name = “bean名字”)
4 MySQL
4.1 MySQL概述
什么是数据库?
- 数据库:DataBase(DB),是存储和管理数据的仓库。
- 数据库管理系统:DateBase Management System(DBMS),操纵和管理数据库的大型软件。
- SQL:Structured Query Language,操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。
MySQL数据模型
- 关系型数据库(RDBMS):建立在关系模型上,由多张相互连接的二维表组成的数据库。
- 特点:使用表存储数据,格式统一便于维护。使用SQL语言操作,标准统一,使用方便,可用于复杂查询。
SQL简介
- SQL:一门操作关系型数据库的编程语言,定义操作所有关系型数据库的统一标准。
- 通用语法
- SQL语句可以单行或者多行书写,以分号结尾。
- SQL语句可以使用空格和缩进来增加语句的可读性。
- MySQL数据库的SQL语句不区分大小写。
- 注释:
- 单行注释:– 注释内容 # 注释内容(MySQL独有)
- 多行注释:/* 注释内容*/
SQL分类
SQL语句通常被分为四大类:
分类 | 全称 | 说明 |
---|---|---|
DDL | Data Definition Languages | 数据定义语言,定义数据库对象(数据库,表,字段) |
DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改查 |
DQL | Data Query Language | 数据查询语言,用来查询数据库中表的的记录 |
DCL | Data Control Language | 数据控制语言,用来创建用户数据库用户,控制数据库的访问权限 |
4.2 数据库设计-DDL
数据库操作
- 查询
- 查询所有数据库:show databases;
- 查询当前数据库:select database();
- 使用
- 使用数据库:use 数据库名;
- 创建
- 创建数据库:create database [if not exists] 数据库名;
- 删除
- 删除数据库:drop database [if exists] 数据库名;
表操作
- 创建
create table 表名(字段1 字段类型 [约束] [comment 字段1注释],...,)[comment 注释]
- 约束:约束是作用于表中字段上的规则,用于限制存储在表中的数据。保证数据库中数据的正确性,有效性和完整性。
约束 | 描述 | 关键字 |
---|---|---|
非空约束 | 限制字段值不为NULL | not null |
唯一约束 | 保证字段值的所有数据唯一、不重复 | unique |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | primary key(auto_increment自增) |
默认约束 | 保存数据时,如果未指定该字段值,则采用默认值 | default |
外键约束 | 让两张表的数据建立连接,保证数据的一致性和完整性 | foreign key |
- 查询
- 查询当前数据库所有表
show tables
- 查询表结构
desc 表名
- 查询建表语句:
show create table 表名
- 查询当前数据库所有表
- 修改
- 添加字段:
alter table 表名 add 字段名 类型(长度) [comment 注释] [约束]
- 修改字段类型:
alter table 表名 modify 字段名 新数据类型(长度)
- 修改字段和字段类型:
alter table 表名 change 旧字段名 新字段名 类型(长度)[comment 注释] [约束]
- 删除字段:
alter table 表名 drop column 字段名
- 修改表名:
rename table 表名 to 新表名
- 添加字段:
- 删除
- 删除表:
drop table [if exists] 表名
- 删除表:
4.3 数据库操作-DML
- 添加数据
INSERT
- 指定字段添加数据:
insert into 表名(字段名1,字段名2) values (值1,值2)
- 全部字段添加数据:
insert into 表名 values (值1,值2,...)
- 批量添加数据(指定字段):
insert into 表名(字段名1,字段名2) values (值1,值2),(值1,值2)
- 批量添加数据(全部字段):
insert into 表名 values (值1,值2,...),(值1,值2,...)
- 指定字段添加数据:
- 修改数据
UPDATE
- 修改数据:
update 表名 set 字段名1 = 值1 , 字段名2 = 值2, ... [where 条件]
- 修改数据:
- 删除数据
DELETE
- 删除数据:
delete from 表名 [where 条件]
- 删除数据:
4.4 数据库操作-DQL
关键字:SELECT
|
|
DQL-基本查询
- 查询多个字段:
SELECT 字段1,字段2,字段3 FROM 表名
- 查询所有字段:
SELECT * FROM 表名
- 设置别名:
SELECT 字段1[AS 别名] ,字段2[AS 别名] FROM 表名
- 去除重复记录:
SELECT DISTINCT 字段列表 FROM 表名
DQL-条件查询
- 条件查询:
SELECT 条件列表 FROM 表名 WHERE 条件列表
比较运算符 | 功能 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
= | 等于 |
<> 或 != | 不等于 |
between … and … | 在某个范围之内(含最小、最大值) |
in(…) | 在in之后的列表中的值,多选一 |
like 占位符 | 模糊匹配(_匹配单个字符, %匹配任意个字符) |
is null | 是null |
逻辑运算符 | 功能 |
---|---|
and 或 && | 并且 (多个条件同时成立) |
or 或 || | 或者 (多个条件任意一个成立) |
not 或 ! | 非 , 不是 |
DQL-分组查询
聚合函数:将一列数据作为一个整体,进行纵向计算。select 聚合函数(字段列表) from 表名 ;
函数 | 功能 |
---|---|
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
分组查询:select 字段列表 from 表名 [ where 条件 ] group by 分组字段名 [ having 分组后过滤条件 ];
where和have的区别:
-
执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
-
判断条件不同:where不能对聚合函数进行判断,而having可以。
注意事项:
- 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
- 执行顺序: where > 聚合函数 > having 。
DQL-排序查询
- 条件查询:
select 字段列表 from 表名 [ where 条件列表 ] [ group by 分组字段 ] order by 字段1 排序方式1 , 字段2 排序方式2
排序方式:
- ASC:升序(默认值)
- DESC:降序
DQL-分页查询
- 分页查询:
select 字段列表 from 表名 limit 起始索引, 查询记录数 ;
函数:
- if(表达式, tvalue, fvalue):当表达式为true时,取值tvalue;当表达式为false时,取值fvalue
- case expr when value1 then result1 [when value2 then value2 …] [else result] end
4.5 多表设计
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:
- 一对多(多对一)
- 多对多
- 一对一
一对多
一对多关系实现:在数据库表中多的一方,添加字段,来关联一的一方的主键。
问题:部门数据可以直接删除,然而还有部分员工归属于该部门下,此时就出现了数据的不完整、不一致问题。
目前上述的两张表,在数据库层面,并未建立关联,所以是无法保证数据的一致性和完整性的。
此时需要外键约束。
|
|
物理外键
概念:使用 foreign key 定义外键关联另外一张表。
缺点:
-
影响增、删、改的效率(需要检查外键关系)。
-
仅用于单节点数据库,不适用与分布式、集群场景。
-
容易引发数据库的死锁问题,消耗性能。
逻辑外键
-
概念:在业务层逻辑中,解决外键关联。
-
通过逻辑外键,就可以很方便的解决上述问题。
一对一
-
案例: 用户 与 身份证信息 的关系
-
关系: 一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他字段放在另一张表中,以提升操作效率
-
实现: 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
多对多
-
案例: 学生 与 课程的关系
-
关系: 一个学生可以选修多门课程,一门课程也可以供多个学生选择
-
实现: 建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
4.6 多表查询
概述
-
多表查询: 指从多张表中查询数据
-
笛卡尔积: 笛卡尔乘积是指在数学中,两个集合(A集合 和 B集合)的所有组合情况。(在多表查询时,需要消除无效的笛卡尔积)
分类
- 连接查询
- 内连接:相当于查询A、B交集部分数据
- 外连接
- 左外连接:查询左表所有数据(包括两张表交集部分数据)
- 右外连接:查询右表所有数据(包括两张表交集部分数据)
- 子查询
内连接
- 隐式内连接:
SELECT 字段列表 FROM 表1,表2 WHERE 条件
- 显示内连接:
SELECT 字段列表 FROM 表1 [inner] JOIN 表2 on 连接条件
外连接
- 左外连接:
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 连接条件
- 右外连接:
SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 连接条件
子查询
-
介绍:SQL语句中嵌套select语句,称为嵌套查询,又称子查询。
-
形式:
select * from t1 where column1 = ( select column1 from t2 … )
-
子查询外部的语句可以是insert / update / delete / select 的任何一个,最常见的是 select。
-
分类:
- 标量子查询:子查询返回的结果为单个值
- 列子查询:子查询返回的结果为一列
- 行子查询:子查询返回的结果为一行
- 表子查询:子查询返回的结果为多行多列
标量子查询
-
子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式
-
常用的操作符:= <> > >= < <=
列子查询
-
子查询返回的结果是一列(可以是多行)
-
常用的操作符:in 、not in等
-
where xxx in ()
行子查询
-
子查询返回的结果是一行(可以是多列)。
-
常用的操作符:= 、<> 、in 、not in
-
where (xx,xx) = ()
表子查询
-
子查询返回的结果是多行多列,常作为临时表
-
常用的操作符:in
4.7 事务
事务的概念
事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
事务控制
-
开启事务:start transaction; / begin ;
-
提交事务:commit;
-
回滚事务:rollback;
四大特性
4.8 索引
介绍
索引(index)是帮助数据库高效获取数据的数据结构 。
优缺点:
- 优点
- 提高数据查询的效率,降低数据库的IO成本。
- 通过索引列对数据进行排序,降低数据排序的成本,降低CPU消耗。
- 缺点
- 索引会占用存储空间。
- 索引大大提高了查询效率,同时却也降低了insert、update、delete的效率。
结构
MySQL数据库支持的索引结构有很多,如:Hash索引、B+Tree索引、Full-Text索引等。我们平常所说的索引,如果没有特别指明,都是指默认的 B+Tree 结构组织的索引。
-
每一个节点,可以存储多个key(有n个key,就有n个指针)。
-
所有的数据都存储在叶子节点,非叶子节点仅用于索引数据。
-
叶子节点形成了一颗双向链表,便于数据的排序及区间范围查询。
语法
- 创建索引
create [ unique ] index 索引名 on 表名 (字段名,... ) ;
- 查看索引
show index from 表名;
- 删除索引
drop index 索引名 on 表名;
5 JDBC
JDBC简介
JDBC概念:JDBC就是Java语言操作关系型数据库的一套API,全称Java DataBase Connectivity。
JDBC本质:官方定义的一套操作所有关系型数据库的接口,各个数据库公司实现这个接口,提供数据库驱动jar包。我们可以通过这套接口编程,正则执行的代码是驱动jar包中的实现类。
JDBC好处:各个数据库厂商使用相同的接口,java代码不需要对不同数据库分别开发。
JDBC快速入门
- 创建工程,导入驱动jar包。
- 注册驱动
Class.forName("com.mysql.jdbc.Driver")
- 获取连接
Connection conn = DriverManger.getConnection(url,username,password)
- 定义SQL语句
String sql = xxx
- 获取执行SQL对象
Statement stmt = conn.createStatement()
- 执行SQL
stmt.executeUpdate(sql)
- 处理返回结构
- 释放资源
stmt.close() conn,close()
6 Mybatis
什么是Mybatis?
-
MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
-
MyBatis本是 Apache的一个开源项目iBatis, 2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
6.1 MyBatis入门
快速入门
案例:使用Mybatis查询所有用户数据
- 准备工作(创建SpringBoot工程、数据库表User、实体类User)
- 引入MyBatis的相关依赖,配置MyBatis(数据库连接信息)
- 编写SQL语句(注解/XML)
数据库连接池
-
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
-
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
-
释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
连接池优势:
-
资源重用
-
提升系统响应速度
-
避免数据库连接遗漏
lombok
- Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。
注解 | 作用 |
---|---|
@Getter/@Setter | 为所有的属性提供get/set方法 |
@ToString | 会给类自动生成易阅读的 toString 方法 |
@EqualsAndHashCode | 根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法 |
@Data | 提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode) |
@NoArgsConstructor | 为实体类生成无参的构造器方法 |
@AllArgsConstructor | 为实体类生成除了static修饰的字段之外带有各参数的构造器方法。 |
6.2 MyBatis基础增删改查
根据主键删除
SQL语句:delete from emp where id = 17;
接口方法:
|
|
注意:如果mapper接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。
日志输出
- 可以在application.properties中,打开mybatis的日志,并指定输出到控制台。
|
|
- 为什么采用预编译SQL
- 性能更高 一次编译,多次运行。
- 更安全(防止SQL注入) SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。
- 参数占位符
新增
- SQL语句
|
|
- 接口方法
|
|
- 主键返回
|
|
更新
- SQL语句
|
|
- 接口方法
|
|
查询(根据ID查询)
- SQL语句
|
|
- 接口方法
|
|
-
数据封装
-
实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装。
-
如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装。
-
解决方法:
- 起别名,在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样。
1 2
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id} ") public Emp getById(Integer id);
- 手动结果映射,通过 @Results及@Result 进行手动结果映射。
1 2 3 4 5 6
@Select("select * from emp where id = #{id}") @Results({ @Result(column = "dept_id", property = "deptId"), @Result(column = "create_time", property = "createTime"), @Result(column = "update_time", property = "updateTime")}) public Emp getById(Integer id);
- 开启驼峰命名,如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射。
1 2
#开启驼峰命名自动映射,即从数据库字段名 a_column 映射到Java 属性名 aColumn。 mybatis.configuration.map-underscore-to-camel-case=true
-
查询(根据条件查询)
- SQL语句
|
|
- 接口方法
|
|
XML映射文件
规范:
-
XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
-
XML映射文件的namespace属性为Mapper接口全限定名一致。
-
XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。
6.3 MyBatis动态SQL
什么是动态SQL?
定义:随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。
<if>
<if>
:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。`
<where>
:where 元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND 或OR.
<set>
:动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)
<foreach>
|
|
-
collection:集合名称
-
item:集合遍历出来的元素/项
-
separator:每一次遍历使用的分隔符
-
open:遍历开始前拼接的片段
-
close:遍历结束后拼接的片段
<sql><include>
|
|
提升sql语句的复用性。
三、SSM
1 Web后端案例基础-增删改查(SpringBootWeb案例)
1.1 准备工作
需求
-
部门管理
-
查询部门列表
-
删除部门
-
新增部门
-
修改部门
-
-
员工管理
- 查询员工列表(分页、条件)
- 删除员工
- 新增员工
- 修改员工
环境搭建
-
准备数据库表(dept、emp)
-
创建springboot工程,引入对应的起步依赖(web、mybatis、mysql驱动、lombok)
-
配置文件application.properties中引入mybatis的配置信息,准备对应的实体类
-
准备对应的Mapper、Service(接口、实现类)、Controller基础结构
开发规范
案例基于当前最为主流的前后端分离模式进行开发。
- REST(REpresentational State Transfer),表述性状态转换,它是一种软件架构风格
传统风格:
http://localhost:8080/user/getById?id=1 GET:查询id为1的用户
http://localhost:8080/user/saveUser POST:新增用户
http://localhost:8080/user/updateUser POST:修改用户
http://localhost:8080/user/deleteUser?id=1 GET:删除id为1的用户
Rest风格:
http://localhost:8080/users/1 GET:查询id为1的用户
http://localhost:8080/users POST:新增用户
http://localhost:8080/users PUT:修改用户
http://localhost:8080/users/1 DELETE:删除id为1的用户
注意:
-
REST是风格,是约定方式,约定不是规定,可以打破。
-
描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books
1.2 部门管理
查询部门
删除部门
新增部门
路径抽取
一个完整的请求路径,应该是类上的 @RequestMapping 的value属性 + 方法上的 @RequestMapping的value属性。
1.3 员工管理
分页查询
分页插件PageHelper
条件分页查询
删除员工
新增员工
文件上传
-
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
-
文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。
本地存储
|
|
在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M。如果需要上传大文件,可以进行如下配置:
|
|
云存储
阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
|
|
查询回显
更新员工信息
1.4 配置文件
参数配置化
- @Value 注解通常用于外部配置的属性注入,具体用法为: @Value("${配置文件中的key}")
yml配置文件
SpringBoot提供了多种属性配置方式
- application.properties
|
|
- application.yml
|
|
- application.yaml
|
|
yml
基本语法
-
大小写敏感
-
数值前边必须有空格,作为分隔符
-
使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
-
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
-
#
表示注释,从这个字符一直到行尾,都会被解析器忽略
数据格式
对象/map集合:
|
|
数组/List/Set集合:
|
|
@ConfigurationProperties
@ConfigurationProperties 与 @Value
相同点:
- 都是用来注入外部配置的属性的。
不同点:
-
@Value注解只能一个一个的进行外部属性的注入。
-
@ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中。
2 Web后端案例基础-登录认证
2.1 登录功能
基础登录功能
2.2 登录校验
登录校验概述
登录标记:会话技术
统一拦截:过滤器Filter、拦截器Interceptor
会话技术
- 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
- 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
- 会话跟踪方案:
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
- 令牌技术
会话跟踪方案一:Cookie
-
优点:HTTP协议中支持的技术
-
缺点:
- 移动端APP无法使用Cookie
- 不安全,用户可以自己禁用Cookie
- Cookie不能跨域
跨域区分三个维度:协议、IP/域名、端口
会话跟踪方案二:Session
-
优点:存储在服务端,安全
-
缺点:
- 服务器集群环境下无法直接使用Session
- Cookie的缺点
会话跟踪方案三:令牌技术
-
优点:
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器端存储压力
-
缺点:需要自己实现
JWT令牌
-
全称:JSON Web Token (https://jwt.io/)
-
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
-
组成:
- 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
- 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
JWT-生成
- 引入依赖:
|
|
- 生成JWT
|
|
- 校验JWT
|
|
JWT令牌-登录后下发
-
引入JWT令牌操作工具类。
-
登录完成后,调用工具类生成JWT令牌,并返回。
过滤器Filter
-
概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
-
过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
-
过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。
过滤器快速入门
- 定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法。
- 配置Filter:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件
过滤器详解
执行流程
拦截路径
- Filter 可以根据需求,配置不同的拦截资源路径:
拦截路径 | urlPatterns值 | 含义 |
---|---|---|
拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
目录拦截 | /emps/* | 访问/emps下的所有资源,都会被拦截 |
拦截所有 | /* | 访问所有资源,都会被拦截 |
过滤器链
- 介绍:一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。
- 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。
过滤器登录校验-Filter
拦截器Interceptor
-
概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
-
作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
拦截器快速入门
-
定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
-
注册拦截器
拦截器详解
- 拦截器可以根据需求,配置不同的拦截路径:
拦截路径 | 含义 | 举例 |
---|---|---|
/* | 一级路径 | 能匹配/depts,/emps,/login,不能匹配 /depts/1 |
/** | 任意级路径 | 能匹配/depts,/depts/1,/depts/1/2 |
/depts/* | /depts下的一级路径 | 能匹配/depts/1,不能匹配/depts/1/2,/depts |
/depts/** | /depts下的任意级路径 | 能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |
Filter和Interceptor区别
-
接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
-
拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。
2.3 异常处理
程序开发过程中不可避免的会遇到异常现象,出现异常时,默认返回的结果不符合规范
全局异常处理器
3 事务管理
3.1 事务回顾
事务是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。
-
开启事务(一组操作开始前,开启事务):start transaction / begin ;
-
提交事务(这组操作全部成功后,提交事务):commit ;
-
回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;
3.2 Spring事务管理
案例:解散部门:删除部门,同时删除该部门下的员工
注解:@Transactional
位置:业务(service)层的方法上、类上、接口上
作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
3.3 事务进阶
rollbackFor
- 默认情况下,只有出现 RuntimeException 才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务。
- @Transaction(rollbackFor = Exception.class)
propagation
- 事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
- @Transaction(propagation = Prapagation.REQUIRED)
属性值 | 含义 |
---|---|
REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
MANDATORY | 必须有事务,否则抛异常 |
NEVER | 必须没事务,否则抛异常 |
… |
- REQUIRED :大部分情况下都是用该传播行为即可。
- REQUIRES_NEW :当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。
4 AOP
4.1 AOP基础
AOP概述
- AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。
- 场景:
- 案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时
- 实现:
- 动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。
AOP快速入门
案例:统计各个业务层方法执行耗时
- 导入依赖:
|
|
- 编写AOP程序,针对于特定方法根据业务需要进行编程
|
|
场景:
- 记录操作日志
- 权限控制
- 事务管理
优势:
- 代码无侵入
- 减少重复代码
- 提高开发效率
- 维护方便
AOP核心概念
- 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
- 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
"execution(* com.learning.service.*.*(..))"切入点表达式
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
- 目标对象:Target,通知所应用的对象
4.2 AOP进阶
通知类型
- @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行
注意事项
- @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
- @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值。
@PointCut
该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可
通知顺序
当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。
-
不同切面类中,默认按照切面类的类名字母排序:
- 目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
-
用 @Order(数字) 加在切面类上来控制顺序
- 目标方法前的通知方法:数字小的先执行
- 目标方法后的通知方法:数字小的后执行
切入点表达式
切入点表达式:描述切入点方法的一种表达式
作用:主要用来决定项目中的哪些方法需要加入通知
常见形式:
- execution(……):根据方法的签名来匹配
- @annotation(……) :根据注解匹配
切入点表达式-execution
execution 主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中带 ? 的表示可以省略的部分
- 访问修饰符:可省略(比如: public、protected)
- 包名.类名: 可省略
- throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
可以使用通配符描述切入点
*
:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
execution(* com.*.service.*.update*(*))
..
:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
execution(* com.itheima..DeptService.*(..))
根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。
书写建议
- 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是 find 开头,更新类方法都是 update开头。
- 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
- 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用 ..,使用 * 匹配单个包。
切入点表达式-@annotation
@annotation 切入点表达式,用于匹配标识有特定注解的方法。
@annotation(com.learning.anno.Log)
|
|
连接点
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
- 对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
- 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型
4.3 AOP案例
案例:记录操作日志,日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
步骤:
-
准备:
- 在案例工程中引入AOP的起步依赖
- 导入资料中准备好的数据库表结构,并引入对应的实体类
-
编码:
- 自定义注解 @Log
- 定义切面类,完成记录操作日志的逻辑
5 SpringBoot原理
5.1 配置优先级
SpringBoot 中支持三种格式的配置文件,按优先级从大到小排序:
- properties
- yml
- yaml
SpringBoot 除了支持配置文件属性配置,还支持Java系统属性和命令行参数的方式进行属性配置。优先级高于配置文件。
- Java系统属性:
-Dserver.port=9000
- 命令行参数:
--server.port=10010
(优先级更高)
5.2 Bean管理
获取Bean
默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
通过注入IOC容器对象ApplicationContext,调用以下方法完成指定内容。
- 根据name获取bean:
Object getBean(String name)
- 根据类型获取bean:
<T> T getBean(Class<T> requiredType)
- 根据name获取bean(带类型转换):
<T> T getBean(String name, Class<T> requiredType)
Bean作用域
- Spring支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同 名称 的 bean 只有一个实例(单例)(默认) |
prototype | 每次使用该 bean 时会创建新的实例(非单例) |
request | 每个请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
可以通过 @Scope 注解来进行配置作用域:
|
|
注意事项:
- 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)。
- prototype的bean,每一次使用该bean的时候都会创建一个新的实例。
- 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
第三方Bean
如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,就需要用到 @Bean注解。
|
|
若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。
|
|
注意事项:
- 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
- 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
5.3 SpringBoot管理
起步依赖
原理就是maven的依赖传递。
自动配置
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
自动配置原理
- 方案一:@ComponentScan 组件扫描
|
|
- 方案二:@Import 导入。使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:
- 导入 普通类
- 导入 配置类
- 导入 ImportSelector 接口实现类
- @EnableXxxx注解,封装@Import注解
|
|
@SpringBootApplication
该注解标识在SpringBoot工程引导类上,是SpringBoot中最最最重要的注解。该注解由三个部分组成:
-
@SpringBootConfiguration:该注解与 @Configuration 注解作用相同,用来声明当前也是一个配置类。
-
@ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
-
@EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解。
@Conditional
作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中。
位置:方法、类
- @Conditional 本身是一个父注解,派生出大量的子注解:
- @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器。
- @ConditionalOnMissingBean:判断环境中没有对应的bean(类型 或 名称) ,才注册bean到IOC容器。
- @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器。
案例:自定义starter
需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliyunOSSUtils 的自动配置。
目标:引入起步依赖引入之后,要想使用阿里云OSS,注入 AliyunOSSUtils直接使用即可。
步骤:
- 创建 aliyun-oss-spring-boot-starter 模块
- 创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中引入该模块
- 在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
Javaweb总结: