Web开发
web前端
前端的代码如何转换成网页
通过浏览器的内核转化(解析和渲染)成用户看到的网页
web标准
- 也叫网页标准,又一系列标准组成,大部分由W3C(World Wide Web Consortium,万维网联盟)负责制定。
- 三个组成部分:
- HTML:负责网页的结构(页面元素和内容)
- CSS:负责网页的表现(页面元素的外观、位置等页面样式,如:颜色、大小等)
- JavaScript:负责网页的行为(交互效果,如:轮播图)
HTML、CSS
定义
HTML(HyperText Markup Language):超文本标记语言
- 超文本:超越了文本的限制,处理文字信息,还可以定义图片、音频、视频等内容
- 标记语言:由标签构成的语言
- HTML语言都是预定义好的,如:使用<a>展示超链接,<img>展示图片,<video>展示视频
- HTML代码直接在浏览器中运行,HTML标签由浏览器解析
CSS(Cascading Style Sheet):层叠样式表,用于控制页面的样式(表现)。
HTML的结构标签示例
1 | <html> |
HTML的一些语法特点
- 标签不区分大小写
- 标签的属性既可以使用双引号,也可以使用单引号
- 语法结构松散(语法不严格)
CSS引入方式
行内样式(不推荐):写在标签的style属性中
只针对当前一个标签
格式:属性名:属性值;
1
<h1> style="xxx: xxx; xxx: xxx;">标题</h1>
内嵌样式:写在style标签中(可以写在页面任何位置,但通常约定在head标签中)
- 对于当前HTML文件的所有该标签都生效
1
2
3
4
5
6<style>
h1 {
xxx: xxx;
xxx :xxx;
}
</style>外联样式:写在一个单独的.css文件中(通过link标签从网页中引入)(link写在<head>中)
1 | h1 { |
1 | <link rel="stylesheet" href="css/news.css"> |
CSS选择器
用来选取需要设置样式的元素(标签)
- 元素选择器:如上
- id选择器:
1 | #hid { |
1 | <h1 id="hid">CSS id Selector</h1> |
- 类选择器
1 | .cls { |
1 | <h1 class="cls">CSS class Selector</h1> |
优先级:id选择器 > 类选择器 > 元素选择器
页面布局
盒子:页面中所有的元素(标签),都可以看成一个盒子,由盒子将页面的元素包含在一个矩形区域内,通过盒子的视角更方便的进行页面布局。
组成:内容区域(content)、内边距区域(padding)、边框区域(border)、外边距区域(margin)
与<div>和<span>一起使用
HTML实现
图片标签:<img>
格式:<img src=”…” width=”…” height=”…”>
src:图片资源路径
- 绝对路径
- 绝对磁盘路径
- 绝对网络路径
- 相对路径(推荐):./ :当前目录(即HTML文件所在目录)(可省略);../ :上一级目录
- 绝对路径
width:宽度(px,像素;%,相对于父元素的百分比)
height:高度(一般高度和宽度只写一个,就可以等比例缩放)
标题标签:<h1>
只有<h1> 到 <h6>
格式:<h1>……</h1>
水平线标签:<hr>
格式:<hr>
只需写一个<hr>就可以
无意义标签:<div> / <span>
没有语义的布局标签,用于将不是任何标签的文字进行格式的修改
特点:
- <div>:一行只显示一个(独占一行);宽度默认时父元素的宽度,高度默认由内容撑开;可以设置宽高
- <span>:一行可以显示多个(组合行内元素);宽度和高度默认由内容撑开;不可以设置宽高
超链接:<a>
格式:<a href=”…” target=”…”>央视网</a>
属性:href:资源访问的url;target:在何处打开(_self:默认值,在当前页面;_blank:在空白页面打开)
超链接默认蓝色加下划线,如果想修改需要用text-decoration来修改
视频标签:<video>
src:视频的url
controls:显示播放控件
width:宽度
height:高度
音频标签:<audio>
src:音频的url
controls:显示播放控件
段落标签:<p>
文本加粗标签:<b> / <strong>
换行标签:<br>
表格标签:<table> / <tr> / <td>
- <table>:定义表格整体,包含多个<tr>。border:表格边框宽度;width:表格宽度;cellspacing:单元之间的空间
- <tr>:表格的行,包含多个<td>
- <td>:表格单元格(普通),如果是表头单元格,可以替换为<th>(自带居中和加粗)
表单标签:<form>
负责数据的采集,如:注册、登陆等数据的采集
表单项:不同类型的input元素、下拉列表、文本域等
<input>:定义表单项,通过type属性控制输入形式(text(默认)、password(密码字段)、radio(单选按钮)、checkbox(复选框)、file(文件上传)、date/time/datetime-local(日期/时间/日期时间)、number(数字输入框)、email(邮箱输入框)、hidden(隐藏框)、submit/reset/button(提交。重置/可点击按钮))(单选框和复选框中每个input均需要用<label></label>包含,尤其是单选框,表示不可多选)
<select>:定义下拉列表,<option>定义列表项
<textarea>:定义文本域
注意:表单项必须有name属性才可以提交
表单项中value属性可以控制传入的值
属性:
- action:规定当提交表单时向何处发送表单数据—URL(不指定就默认提交到当前页面)
- method:规定用于发送表单数据的方式—POST/GET(默认为GET)
- GET:表单数据拼接在url后面(?username=java),大小有限制
- POST:表单数据在请求体中携带,大小没有限制
CSS实现
颜色:color
格式:color: red;
颜色表示形式
- 关键字:red、blue
- rgb表示法:rgb(0,0,255) (红绿蓝三原色)
- 十六进制表示法:#ff0000 (每两位代表rgb的一位)(可以简写成#f00,即在每个rgb的两位相同时写一个即可)
字体:font-size
记得后面加上px
文本装饰:text-decoration
none:默认,标准文本
underline:下划线
overline:上划线
line-through:穿过文本的一条线
首行缩进:text-indent
常与<p>一起使用
设置行高:line-height
常与<p>一起使用
对齐方式:text-align
包括center、left、right
盒子模型相关:
width
height
box-sizing:指定宽高指的是哪个部分的(eg. border-box)
background-color
padding:内边距(上 右 下 左)(一致时可以只写一个)(写三个时分别为上 左右 下;两个时分别为上下 左右)(可以写auto,代表浏览器自动计算)
border:边框(宽度 线条类型 颜色)
margin:外边框(上 右 下 左)
(如果只设置某一个方位的边框、内边距、外边距,可以在属性名后加上-位置,如:padding-top\padding-left…)
JavaScript
特点
- 跨平台、面向对象的脚本语言(不需要编译)。用来控制网页行为,能使网页可交互
- JS与Java是完全不同的语言,无论是概念还是设计,但是基础语法类似
引入方式
- 内部脚本:将JS代码定义在HTML页面中
- JS代码必须位于<script></script>标签之间
- 在HTML文档中,可以在任意地方放置任意数量的<script>
- 一般会把脚本置于<body>元素的底部,可以改善显示速度
1 | <script> |
- 外部脚本:将JS代码定义在外部JS文件中,然后引入到HTML页面中
- 外部JS文件中,只包含JS代码,不包含<script>标签
- <script>标签不能自闭合(自闭合:本来要用一个配对的结束符号来关闭,然而它却自己关闭了,如:<script src=”js/demo.js”>)
1 | <script src="js/demo.js"></script> |
demo.js 如下:
1 | alert("Hello JS") |
基础语法
- 区分大小写
- 每行结尾分号可写可不写
输出语句:
- 弹出警告框:window.alert()
- 在浏览器中展示:document.write()
- 写入浏览器控制台:console.log()
变量:
- 用var关键字(variable)来声明变量
- JS是一门弱类型语言,变量可以存放不同类型的值
- 变量名需要遵循以下规则:
- 组成字符可以是任何字母、数字、下划线或美元符号$
- 数字不能开头
- 建议使用驼峰命名
特点:
- 作用域大,全局变量
- 可以重复定义
新增:
- let关键字:与var类似,但是是局部变量,而且不能重复定义
- const关键字:声明只读的常量
数据类型:
- 原始类型:number、string、boolean、null、undefined
- 引用类型—object
(使用typeof运算符可以获取数据类型)
运算符:
- 算术运算符
- 赋值运算符
- 比较运算符:(多一个===)
- 逻辑运算符
- 三元运算符
==与===的区别:==会进行类型转换,===不会进行类型转换,===会同时比较数据类型和数据
函数
定义:用function关键字
方式:
方式一
1
2
3function add(a, b){
return a + b;
}方式二
1
2
3var add = function(a, b){
return a + b;
}
注意:
- 形参不需要指明类型
- 返回值不需要指明类型
- 函数调用可以传递任意多个的参数,函数只会取前几个作为参数
对象
Array
定义:
var 变量名 = new Array(元素列表);
var 变量名 = [元素列表];
访问:
arr[索引] = 值;
特点:长度可变,类型可变(可以存储任意类型的数据)
属性:
- length:返回数组元素数量
方法:
- forEach ():遍历数组中有值的元素,并调用一次传入的函数
1 | arr.forEach(function(e)){ |
每次调用function,并将获得的值存入e
可简写为箭头函数:(…) => {…} (小括号中放形参列表)
1 | arr.forEach((e) => { |
- push():在末尾添加新元素,并返回新长度
- splice():删除元素(传两个参:从哪个索引开始,删几个)
String
创建方式:
- var 变量名 = new String(“…”);
- var 变量名 = “…”;
属性:
- length
方法:
- charAt()
- indexOf():检索字符串位置
- trim():去除字符串两边的空格
- substring()
JSON
JS自定义对象:
1 | var 对象名 = { |
函数可省略为: 函数名称 () {}
概念:JavaScript Object Notation,JS对象标记法
- JSON是通过JS对象标记法书写的文本、
- 由于语法简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输
定义:
1 | var 变量名 = '{"key1": value1, "key2": value2}'; |
value的数据类型:
- 数字:直接写整数或浮点数
- 字符串:放在双引号中
- 逻辑值:直接写
- 数组:放在方括号中
- 对象:放在花括号中
- null
JSON字符串转换为JS对象:
var jsObject = JSON.parse(jsonStr);
(转换为对象后就可以通过.属性拿到内部某个属性值)
JS对象转换为JSON字符串
var jsonStr = JSON.stringify(jsObject);
BOM
概念:Browser Object Model,浏览器对象模型,允许JS与浏览器对话,JS将浏览器的各个组成部分封装为对象
组成:
- Window:浏览器窗口对象
- 获取:
- 直接使用window,其中window.可以省略。(比如window.alert(“Hello”)等价于alert(“Hello”))
- 属性
- history
- location
- navigation
- 方法
- alert():显示带有一段消息和一个确认按钮的警告框
- confirm():显示带有一段消息以及确认按钮和取消按钮的对话框(返回布尔值)
- setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式(执行多次)
- setTimeout():在指定的毫秒数后调用函数或计算表达式(执行一次)
- 获取:
- Navigator:浏览器对象
- Screen:屏幕对象
- History:历史记录对象
- Location:地址栏对象
- 介绍:地址栏对象
- 获取:使用windows.location获取,其中windows.可以省略
- 属性:
- href:设置或返回完整的URL
DOM
概念:Document Object Model,文档对象模型
分类:将标记语言的各个组成部分封装为对应的对象
- Document:整个文档对象
- Element:元素对象(每一个标签)
- Attribute:属性对象
- Text:文本对象
- Comment:注释对象
作用:
- 改变HTML元素的内容
- 改变HTML元素的样式(CSS)
- 对HTML DOM事件作出反应
- 添加和删除HTML元素
组成:
- Core DOM - 所有文档类型的标准模型
- Document:整个文档对象
- Element:元素对象(每一个标签)
- Attribute:属性对象
- Text:文本对象
- Comment:注释对象
- XML DOM - XML文档的标准模型
- HTML DOM - HTML文档的标准模型
- Image:<img>
- Button:<input type=’button’>
- ……
获取方式:
- HTML中的Element对象可以通过Document对象获取,而Document对象是通过window对象获取的
- Document对象中提供了以下获得Element元素对象的函数:
- 根据id属性值,返回当Element对象:var h1 = document.getElementById(‘h1’);
- 根据标签名,返回数组:getElementsByTagName
- 根据name属性值,返回数组:getElementsByName
- 根据class属性值,返回数组:getElementsByClassName
事件监听
事件:
HTML事件是发生在HTML元素上的”事情“。比如:点击按钮、按下键盘……
事件监听:
JS可以在事件被侦测到时执行代码
事件绑定
- 方式一:通过HTML标签中的事件属性进行绑定
1 | <input type="button" onclick="on()" value="按钮1"> |
- 方式二:通过DOM元素属性进行绑定
1 | <input type="button" id="btn" value="按钮2"> |
常见事件
- onclick:点击
- onblur:失去焦点
- onfocus:获得焦点
- onload:页面或图像完全加载
- onsubmit:表单提交
- onkeydown:按下键盘上某个键
- onmouseover:鼠标移到某元素之上
- onmouseout:鼠标从某元素移开
Vue
概述
是一套前端框架,免除原生JS中的DOM操作,简化书写。
基于MVVM(Model-View-ViewModer)思想,实现数据的*双向绑定**,将编程的关注点放在数据上。
格式:
- 新建HTML页面,引入Vue.js文件
1 | <script src="js/vue.js"></script> |
- 在JS代码区域,创建Vue核心对象,定义数据类型
1 | <script> |
- 编写视图
1 | <div id="app"> |
插值表达式:
- 形式:
- 内容可以是:变量、三元运算符、函数调用、算术运算
指令
- v-bind:动态绑定属性值,如:href、css样式等
- v-model:为表单元素创建双向数据绑定(可简写为@)
- v-on:为html标签添加事件
- v-if:为true时渲染某元素,否则不渲染(就是没有了)
- v-else-if:跟if组合用
- v-else:跟if组合用
- v-show:展示某元素(区别:切换的是display属性的值,true则展示,否则隐藏,而不是没有)
- v-for:列表渲染,变量容器的元素或对象的属性
注意:
- 通过v-bind或者v-model绑定的变量,必须在数据模型中声明
生命周期
概念:指一个对象从创建到销毁的整个过程
八个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)
- beforeCreate
- created
- beforeMount
- mounted:挂载完成——Vue初始化成功,HTML页面渲染成功。(发送请求到服务端,加载数据)
- beforeUpdate
- updated
- beforeDestroy
- destroyed
组件
以.vue结尾
组成部分:
- <template>:模板部分,由它生成HTML代码
- <script>:控制模板的数据来源和行为,相当于js文件
- <style>:css样式部分
开发流程
- 创建页面,完成页面的整体布局规划
- 布局中各个部分的组件实现
- 列表数据的异步加载,并渲染展示
路由
前端路由:URL中的hash(#号)与组件之间的对应关系
Vue Router:
组成:
- VueRouter:路由器类,根据路由请求在路由视图中动态渲染选中的组件
- <router-link>:请求链接组件,浏览器会解析为<a>
- eg. <router-link to=”/dept”>部门</router-link>
- <router-view>:动态视图组件,用来渲染展示与路由路径对应的组件
- eg. 写在APP.vue的<template>中:<router-view></router-view>
web后端
maven
是一款管理和构建java项目的工具
作用
- 依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
- 统一项目结构:提供标准、统一的项目结构
- 项目构建:标准跨平台的自动化项目构建方式
组成
- groupId:项目隶属组织名称(通常是域名反写)
- artifactId:项目名称
- version:项目版本号
依赖
依赖具有传递性:分为直接依赖和间接依赖
- 为了主动断开依赖的资源,需要排除依赖——<exclusions>(被排除的资源无需指定版本)
依赖范围:用<scope>…</scope>设置其作用范围
- 包括主程序有效、测试程序有效、参与打包运行三种范围
生命周期:为了所有的maven项目构建过程进行抽象和统一,包括以下三套生命周期:
- clean:清理工作
- clean:移除上一次构建生成的文件
- default:核心工作
- compile:编译项目源代码
- test:使用合适的单元测试框架进行测试(junit)
- package:将编译后的文件打包
- install:安装项目到本地仓库
- site:生成报告、发布站点等
注意:在同一套生命周期中当运行后面的阶段时,前面的阶段都会运行。
- clean:清理工作
起步依赖
简化依赖配置,引入起步依赖就相当于引入了这一块业务开发所需要的全部依赖。原理是Maven的依赖传递。
spring-boot-starter-web:包含了web应用开发所需的常见依赖
spring-boot-starter-test:包含了单元测试所需的常见依赖
起步依赖的版本无须声明,在父工程中进行了统一管理
HTTP
概念:
Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
特点:
- 基于TCP协议:面向连接,安全
- 基于请求-响应模型:一次请求对应一次响应
- 无状态:对于事务处理没有记忆能力。每次请求-响应都是独立的。
- 缺点:多次请求间不能共享数据
- 优点:速度快
请求数据格式:
请求行:请求数据第一行(请求方式、资源路径、协议)
请求头:第二行开始,格式key:value
- Host:请求的主机名
- User-Agent:浏览器版本
- Accept:浏览器能接收的资源类型
- Accept-Language:浏览器偏好的语言,服务器可以据此返回不同语言的网页
- Accept-Encoding:浏览器可以支持的压缩类型
- Content-Type:请求主体的数据类型
- Content-Length:请求主体的大小(单位:字节)
请求体:Post请求,存放请求参数
请求方式-GET:请求参数在请求行中,没有请求体,如:/brand/findAll?name=OPPO&status=1。GET请求大小是有限制的。
请求方式-POST:请求参数在请求体中,POST请求大小是没有限制的。
响应格式:
- 响应行:响应数据第一行(协议、状态码、描述)
- 200:客户端请求成功
- 404:请求资源不存在,一般是URL输入错误,或者网站资源被删除了
- 500:服务器发生不可预期的错误
- 响应头:第二行开始,格式key:value
- Content-Type:响应内容的类型
- Content-Length:响应内容的长度(字节数)
- Content-Encoding:响应压缩算法
- Cache-Control:客户端应该如何缓存
- Set-Cookie:告诉浏览器为当前页面所在的域设置cookie
- 响应体:存放响应数据
Web服务器
是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。主要功能是”提供网上信息浏览服务“。
- 对HTTP协议的操作进行封装,简化web程序开发
- 部署web项目,对外提供网上信息浏览服务
Tomcat
- 一个轻量级的web容器,支持servlet、jsp等少量javaEE规范
- 也称为web容器、servlet容器(servlet程序需要依赖于Tomcat才能运行)
(HTTP协议默认端口号为80,如果将Tomcat端口号改为80,则将来访问Tomcat时将不需要输入端口号)
基于SpringBoot开发的web应用程序,内置了tomcat服务器,当启动类运行时,会自动启动内嵌的tomcat服务器。
请求响应
概述
请求响应:
- 请求(HttpServletRequest):获取请求数据
- 响应(HttpServletResponse):设置响应数据
- BS架构:Browser/Server,浏览器/服务器架构模式,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。(优点:维护方便;缺点:体验一般)
- CS架构:Client/Server,客户端/服务器架构模式。(优点:体验好;缺点:开发、维护麻烦)
简单参数
原始方式:
- Controller方法形参中声明HttpServletRequest对象
- 调用对象的getParameter(参数名)
SpringBoot中接收简单参数
- 请求参数名与方法形参变量名相同
- 会自动进行类型转换
@RequestParam注解
- 方法形参名称与请求参数名称不匹配,通过该注解完成映射
- 该注解的required属性默认为true,代表请求参数必须传递
实体参数
简单实体参数:请求参数名与形参对象属性名相同即可
复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可
数组集合参数
数组:请求参数名与形参中数组变量名相同,可以直接使用数组封装
集合:请求参数名与形参中集合变量名相同,通过@RequestParam绑定参数关系(因为默认是用数组传递的)
日期参数
使用@DateTimeFormat注解完成日期参数格式转换
eg.(@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) LocalDateTime updateTime)
JSON参数
JSON数据键名与形参对象属性名相同,需要使用@RequestBody标识
路径参数
通过请求URL直接传递参数,使用{…}来标识路径参数,需要使用**@PathVariable**获取路径参数
一个方法中可以有多个路径参数,每个路径参数前均需要注解
响应
@ResponseBody
- 类型:方法注解、类注解
- 位置:Controller方法/类上
- 作用:将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换成JSON格式响应
- 说明:@RestController=@Controller+@ResponseBody(所以一般写@RestController)
统一响应结果
Result(code, msg, data)
分层解耦
三层架构
为了单一职责原则,一个类或一个方法只做一件事,所以web开发有了三层架构:
- controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据
- service:业务逻辑层,处理具体的业务逻辑
- dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增删改查
好处:复用性强、便于维护、利于扩展
分层解耦
- 内聚:软件中各个功能模块内部的功能联系
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度
- 软件设计原则:高内聚低耦合
控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器)
依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时所依赖的资源。
Bean对象:IOC容器创建、管理的对象
IOC和DI:
- Service层和Dao层的实现类,交给IOC容器管理
- 在类前加上@Component
- 为Controller和Service注入运行依赖的对象
- 在成员变量前加上@Autowired
Bean的声明:
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一
- @Component:声明Bean的基础注解。以下三个都是它的衍生注解。不属于以下三类时使用。
- @Controller:标注在控制器类上。
- @Service:标注在业务类上。
- @Repository:标注在数据访问类上。
注意:
- 声明bean时,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明bean,但在springboot集成web开发中,声明控制器bean只能用@Controller
Bean组件扫描:
- 前面声明的bean四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描
- @ComponentScan注解虽然没有显示配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包
Bean注入:
- @Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报错
- 解决方案:
- @Primary:在@Service前加。
- @Qualifier:在@Autowired后加。eg.@Qualifier(“empServiceA”)
- @Resource:代替@Autowired的位置。eg.@Resource(name=”empServiceB”)
@Resource和@Autowired的区别
- 后者是spring框架提供的注解,而前者是JDK提供的注解
- 后者默认是按照类型注入,而前者默认是按照名称注入
开发规范
Restful
REST(REpresentation State Transfer),表述性状态转换,是一种软件架构风格。
- URL定位资源
- HTTP动词描述操作
- 前后端交互统一响应结果Result(包括code响应码、msg响应信息、data返回数据)
注意:
- REST是风格,是约定方式,不是规定,可以打破
- 描述模块的功能通常使用复数来表示此类资源,而非单个资源
日志小技巧
- 添加注解@Slf4j
- 添加Log.info()
eg.
1 |
|
@RequestMapping
一个完整的请求路径,应该是类上的@RequestMapping的value属性+方法上的@RequestMapping的value属性。
@RequestParam
设置请求参数默认值:
@RequestParam(defaultValue=”1”)
PageHelper分页插件
引入依赖:pagehelper-spring-boot-starter
使用:
- EmpServiceImpl:
1
2
3PageHelper.startPage(pageNum, pageSize);
List<Emp> list = empMapper.list();
Page<Emp> page = (Page<Emp>)list;- EmpMapper:
1
2
public List<Emp> list();
文件上传
简介
- 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程
- 文件上传在项目中应用非常广泛,eg. 发微博、发朋友圈
前端页面三要素
1 | <form action="/upload" method="post" enctyoe="multipart/form-data"> |
- 表单提交方式 method=”post”
- 表单属性 enctyoe=”multipart/form-data”:表单提交时作为多个数据提交
- 表单项 type=”file”
服务端接收文件
1 |
|
- 通过MultipartFile这个API接收上传的文件,上传上来临时文件,当请求响应结束后,临时文件会自动删除
本地存储
将上传的文件存储到本地服务器磁盘中
服务端
1 |
|
修改最大允许上传文件
在SpringBoot中,文件上传,默认单个文件允许最大为1M
1 | #配置单个文件最大上传大小 |
缺点:前端无法直接访问、磁盘空间限制、磁盘损坏
第三方服务—阿里云
通用思路
- 准备工作
- 注册阿里云(实名认证)
- 充值
- 开通对象存储服务(OSS)
- 创建bucket—存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间
- 获取AccessKey(密钥)
- 参考官方SDK编写入门程序
- 集成使用
SDK:Software Development Kit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等
集成步骤:
- 引入阿里云OSS上传文件工具类
1 |
|
- 上传图片接口开发
1 |
|
配置文件(application.properties)
参数配置化
将技术或服务所使用的参数直接配置在配置文件中,交给配置文件进行统一的管理和维护。
java代码中使用**@Value**注解通常用于外部配置的属性注入,具体用法:@Value(“${配置文件中的key}”)
yml格式文件
优势:
- XML:臃肿
- properties:层次结构不清晰
- yml/yaml:简洁,数据为中心(推荐)
基本语法:
- 大小写敏感
- 数值前必须有空格,作为分隔符
- 使用缩进来表示层级关系,缩进时,不允许使用Tab键,只能用空格(但是idea里可以将Tab自动识别为空格)
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略
数据格式:
- 对象/Map集合:
1 | user: |
- 数组/List/Set集合:
1 | hobby: |
@ConfigurationProperties
改进方式
在utils文件夹中添加AliOSSProperties:
1 |
|
原先的AliOSSUtils改为:
1 |
|
@ConfigurationProperties与@Value
相同:
- 都是用来注入外部配置的属性的
不同:
- @Value注解只能一个一个的进行外部属性的注入
- @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中
登录功能
登录校验
会话技术
- 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中包含多次请求和响应。
- 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一个浏览器,以便在同一次会话的多次请求间共享数据。
- 会话跟踪方案:
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
- 令牌技术
Cookie:
- 优点:HTTP协议支持的技术
- 缺点:
- 移动端APP无法使用
- 不安全,用户可以自己禁用
- 不能跨域(跨域的三个维度:协议、IP/域名、端口)
Session:
- 优点:存储在服务端,安全
- 缺点:
- 服务器集群环境下无法直接使用Session
- Cookie的缺点
令牌技术:(主流)
- 优点:
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器端存储压力(不需要服务器端存储任何的数据)
- 缺点:需要自己实现
JWT令牌
JSON Web Token,定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
组成:
- Head(头),记录令牌类型,签名算法。通过Base64编码获得。
- Payload(有效载荷),携带一些自定义信息、默认信息。通过Base64编码获得。
- Signaure(签名),防止Token被篡改,确保安全性。将header、payload加入指定密钥,通过指定签名算法计算而来。
Base64:基于64个可打印字符(A-Z,a-z,0-9,+,/)来进行二进制数据的编码方式
场景:登录认证
- 令牌生成:登录成功后,生成令牌,并返回给前端
- 令牌校验:再请求到达服务端后,对令牌进行统一拦截、校验。后续每个请求,都需要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后再处理
生成:
1 |
|
校验:
1 |
|
注意:
- JWT校验时使用的签名密钥,必须和生成JWT令牌时使用的密钥是配套的
- 如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法
过滤器Filter
概述
- Filter过滤器,JavaWeb三大组件(Servlet、Filter、Listener)之一
- 过滤器可以把资源的请求拦截下来,从而实现一些特殊的功能
- 过滤器一般完成一些通用的操作,如:登录校验、统一编码处理、敏感字符处理等
使用
- 定义Filter:定义一个类,实现Filter接口,并重写其所有方法
1 |
|
- 配置Filter:Filter类加上@WebFilter注解,配置拦截资源的路径,引导类上加@ServletComponentScan开启Servlet组件(Java Web)支持(加在@SpringBootApplication之前)
拦截路径
- 具体路径:/login
- 目录拦截:/emps/*
- 拦截所有:/*
过滤器链
- 一个web应用中,可以配置多个过滤器,多个过滤器形成一个过滤器链
- 顺序:优先级按照过滤器类名(字符串)的自然排序
登录校验过滤器
1 |
|
拦截器Interceptor
概述
- 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
- 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
使用
- 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法
1 |
|
- 注册拦截器
1 |
|
*这里的/*表示拦截所有
拦截路径
- addPathPatterns:需要拦截的资源
- excludePathPatterns:不需要拦截的资源
拦截路径:
- /*:一级路径(包括/depts,不包括/depts/1)
- /**:任意级路径
过滤器于拦截器同时存在
先执行过滤器,过滤器放行后执行拦截器
登录校验拦截器
1 |
|
Filter与Interceptor
- 接口规范不同:前者需要实现Filter接口,后者需要实现HandlerInterceptor接口
- 拦截范围不同:前者拦截所有资源,后者之后拦截Spring环境中的资源
异常处理
方案一
在Controller的方法中进行try…catch处理(代码臃肿,不推荐)
方案二
全局异常处理器(简单,推荐)
1 |
|
@RestControllerAdvice = @ControllerAdvice + @ResponseBody
事务管理&AOP
事务管理
概念
事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败。
操作
- 开启事务(一组操作开始前,开启事务):start transaction / begin;
- 提交事务(这组操作全部成功后,提交事务):commit;
- 回滚事务(中间任何一个操作出现异常,回滚事务):rollback;
注解
- 注解:@Transactional
- 位置:业务(service)层的方法上、类上、接口上
- 作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
事务属性—回滚
rollbackFor
- 默认情况下,只有出现RuntimeException才回滚异常。rollbackFor属性用于控制出现何种的异常类型才会回滚事务。
- @Transactional(rollbackFor = Exception.class) 代表所有的异常都会回滚。
事务属性—传播行为
propagation
- 事务传播行为:指当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
- REQUIRED:(默认值)需要事务,有则加入,无则创建新事务。
- REQUIRES_NEW:需要新事务,无论有无,总是创建新事务。
eg. @Transactional(propagation = Propagation.REQUIRES_NEW) 代表会创建一个新的事务。
当被调用的事务方法和原先的事务方法在一个事务中时,一旦出现问题就会全部回滚,所以用REQUIRES_NEW可以事务之间不影响,比如下订单前需要记录日志,无论订单保存成功与否都需要保证日志记录能够记录成功
AOP
概述
- AOP:Aspect Oriented Programming(面向切片编程、面向方面编程),就是面向特定方法编程。
- 实现:动态代理是面向切面编程最主流的实现,而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定方法进行编程。
- 场景:记录操作日志,权限控制,事务管理……
- 优势:代码无侵入,减少重复代码,提高开发效率,维护方便
开发步骤
场景:统计每一个业务方法的执行耗时
- 导入依赖
- 编写AOP程序:针对于特定方法根据业务需要进行编程
1 |
|
核心概念
- 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
- 通知:Advice,指重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时会被应用
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
- 目标对象:Target,通知所应用的对象
执行流程
一旦进行AOP程序的开发,最终运行的就不再是原始的目标对象,而是基于目标对象所生成的代理对象。
通知类型
- @Aroud:环绕通知,标注的通知方法在目标方法前后都被执行
- @Before:前置通知,标注的通知方法在目标方法前被执行
- @After:后置通知(最终通知),标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning:返回后通知,标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing:异常后通知,标注的通知方法发生异常后执行
注意:
- @Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行
- @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值
@PointCut
该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可。
1 |
|
private:仅能在当前切面类中引用
public:在其他外部的切面类中也能引用
通知顺序
当有多个切面的切入点都匹配了目标方法时,多个通知方法都会被执行。
- 不同切面类中,默认按照切面类的类名字母顺序
- 目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
- 用@Order(数字)加在切面类上来控制顺序
- 目标方法前的通知方法:数字小的先执行
- 目标方法后的通知方法:数字小的后执行
切入点表达式
execution(…):根据方法的签名来匹配
主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配
语法:execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中?表示可省略:
- 访问修饰符:比如pulic,protected
- 包名.类名.:不建议省略
- throws 异常:是方法上声明抛出的异常,不是实际抛出的异常
通配符:
- *:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名,任意类型的一个参数,也可以通配包、类、方法名的一部分
- ..:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
注意:根据业务需要,可以使用&&、||、!来组合比较复杂的切入点表达式
书写建议:
- 所有业务方法名在命名时尽量规范。方便切入点表达式快速匹配(如:查询类方法均以find开头等)
- 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性
- 在满足业务需要前提下,尽量缩小切入点的匹配范围(如:包名匹配尽量不使用..,使用*匹配单个包)
@annotation(…):根据注解匹配
用于匹配标识有特定注解的方法
eg. @annotation(com.itheima.aop.MyLog)可以匹配所有有@MyLog注解的方法
需要在com.itheima.aop目录下新建一个命名为MyLog的Annotation:
1 | //运行时有效 |
连接点
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
- 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint
- 对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型
示例:
- joinPoint.getTarget().getClass().getName() // 获取目标类名
- joinPoint.getSignature() // 获取目标方法签名
- joinPoint.getSignature().getName() // 获取目标方法名
- joinPoint.getArgs() // 获取目标方法运行参数
获取当前用户
获取request对象,从请求头中获取到jwt令牌,解析令牌获取出当前用户的id
1 |
|
SpringBoot
配置
properties > yml > yaml
虽然SpringBoot支持多种格式配置文件,但是在项目开发时,推荐使用统一的一种配置(yml是主流)
Bean管理
获取bean
- 默认在Spring项目启动后,会把bean都创建好放在IOC容器中(主要针对于默认的单例非延迟加载的bean,正常情况下还会受到作用域和延迟初始化影响),如果想要主动获得这些bean,方式如下:
- 根据name获取bean:Object getBean(String name)
- 根据类型获取bean:<T> T getBean(Class<T> requiredType)
- 根据name获取bean(带类型转换):<T> T getBean(Stirng name, Class<T> requiredType)
bean的作用域
- singleton:容器中同名称的bean只有一个实例(单例)(默认)
- prototype:每次使用该bean时会创建新的实例(非单例)
通过@Scope注解来配置作用域
eg.
1 | //@Lazy |
注意:
- 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
- 实际开发大部分的bean是单例的,一般不需要配置Scope属性
第三方bean
如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解
1 |
|
若要管理第三方bean对象,建议进行集中分类配置,可以通过@Configuration注解声明一个配置类
1 | //配置类 |
注意:
- 通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
- 如果第三方bean需要依赖其他的bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配
@Component及衍生注解与@Bean注解的使用场景
- 项目中自定义的使用@Component及衍生注解
- 项目中引入第三方的使用@Bean注解
SpringBoot原理
起步依赖
maven的依赖传递
自动配置
当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要手动去声明,从而简化了开发,省去了繁琐的配置操作。
自动配置方案
- 方案一:@ComponentScan组件扫描
1 | // 还需要包括原先的目录,因为是声明后是覆盖关系 |
使用繁琐,性能低
- 方案二:@Import导入。使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要包括:
- 导入普通类
- 导入配置类
- 导入ImportSelector接口实现类
- @EnableXxx注解,封装@Import注解(推荐)
1 |
|
自动配置原理
@SpringBootApplication
该注解标识在SpringBoot工程引导类上,是SpringBoot中最重要的注解,由三部分组成:
- @SpringBootConfiguration:该注解与@Configuration注解作用相同,用来声明当前也是一个配置类
- @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包
- @EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解
注意:SpringBoot会根据@Conditional注解条件装配,而不是全部注册为IOC容器的bean。
@Conditional
- 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring IOC容器中
- 位置:方法、类
- @Conditional本身是一个父注解,派生出大量的子注解:
- @ConditionalOnClass:判断环境中是否有对应字节码文件(name = “…”),有才注册bean到IOC容器
- @ConditionalOnMissingBean:判断环境中是否有对应的bean(可以根据类型value属性或名称name属性来判断是否存在),没有才注册bean到IOC容器。通常用来设置一个默认的bean对象。
- @ConditionalOnProperty:判断配置文件中是否有对应属性和值(name = “…”, havingValue = “…”),有才注册bean到IOC容器
自定义starter
在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot的starter。
起步依赖分类:
- SpringBoot官方:spring-boot-starter-xxx
- 其他技术提供:xxx-spring-boot-starter
eg.
需求:自定义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/xxx.imports
Maven高级
分模块设计与开发
分模块设计:将项目按照功能拆分成若干个子模块
原因:方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享
注意:分模块开发需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分。
继承与聚合
继承关系
继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承
作用:简化依赖配置、统一管理依赖
实现:<parent>…</parent>
- 创建maven模块tlias-parent,该工程为父工程,设置打包方式为pom(默认jar)
- <packaging>pom</packaging>
- 在子工程的pom.xml文件中,配置继承关系
- <relativePath>../tlias-parent/pom.xml</relativePath>
- 在父工程中配置各个工程共有的依赖(子工程会自动继承父工程的依赖)
打包方式:
- jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)
- war:普通web程序打包,需要部署在外部的tomcat服务器中运行
- pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理
版本锁定
在maven中,可以在父工程的pom文件中通过<dependencyManagement>来统一管理依赖版本
注意:子工程引入依赖时,无需指定<version>版本号,父工程统一管理。变更依赖版本,只需在父工程中统一变更。
自定义属性/引用属性:放在<properties>…</properties>中
<dependencyManagement>与<dependencies>的区别:
- 后者是直接依赖,在父工程配置了依赖,子工程会直接继承下来
- 前者是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)
聚合
聚合:将多个模块组织成一个整体,同时进行项目的构建
聚合工程:一个不具有业务功能的”空“工程(有且仅有一个pom文件)(所以使用父工程作为聚合工程)
作用:快速构建项目(无需根据依赖关系手动创建,直接在聚合工程上构建即可)
写法:maven中可以通过<modules>设置当前聚合工程所包含的子模块名称
1 | <modules> |
注意:聚合工程所包含的模块,在构建时,会自动根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关。
继承与聚合:
- 作用
- 聚合用于快速构建项目
- 继承用于简化依赖配置、统一管理依赖
- 相同点:
- pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
- 均属于设计类模块,并无实际的模块内容
- 不同点:
- 聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些
- 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
私服
介绍
私服是一种特殊的远程仓库,架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。
依赖查找顺序:
- 本地仓库
- 私服
- 中央仓库
注意:私服在企业项目开发中,一个项目/公司,只需要一台即可。
资源上传与下载
- 设置私服的访问用户名/密码(settings.xml中的servers中配置)
- IDEA的maven工程的pom文件中配置上传(发布)地址
- 设置私服依赖下载的仓库组地址(settings.xml中的mirrors、profiles中配置)
- 执行deploy
项目版本:
- RELEASE(发行版本):功能趋于稳定,当前更新停止,可以用于发行的版本,存储在私服中的RELEASE仓库中
- SNAOSHOT(快照版本):功能不稳定、尚处于开发中的版本,存储在私服中的SNAOSHOT仓库中



