JavaWeb学习笔记

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快速入门

  1. 新建文本文件,后缀名改为.html
  2. 编写HTML结构标签
  3. <body>中填写内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
    <head>
        <title>
            HTML快速入门
        </title>
    </head>
    <body>
        <h1>Hello HTML</h1>
        <img src="1.png"/>
    </body>
</html>

特点:

  • HTML标签不区分大小写
  • HTML标签属性值单双引号都可以
  • HTML语法松散

基础标签&样式

以新浪新闻为例

  • 新浪新闻-标题
    • 标题排版
    • 标题样式
    • 超链接
  • 新浪新闻-正文
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<!--vscode中输入感叹号加回车一键生成-->
<!-- 文档类型为html ctrl+shift+/注释 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <!-- 字符集为utf-8 -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>焦点访谈:中国底气 新思想夯实大国粮仓</title>
    <!-- 方式二:内嵌样式 -->
    <style>
        h1 {
            color: #4d4f53;
        }

        span {
            color: #968d92;
            font-size: 15px;
        }

        a {
            color: black;
            text-decoration: none;
            /* 设置文本为标准文本 */
        }

        p {
            text-indent: 35px;
            /* 设置首行缩进 */
            line-height: 40px;
            /* 设置行高 */
        }

        #plast {
            text-align: right;
        }
        #center {
            width: 65%;
            margin: 0% 17.5% 0% 17.5%;
        }
    </style>
    <!-- <link rel="stylesheet" href="css/news.css"> -->
</head>

<body>
    <div id="center">
        <!-- 
    img标签:
    src:图片资源路径
    width:宽度 单位为px像素,或者百分比 若只设置高度或者宽度,另一个元素会等比例缩放
    height:高度 
    路径书写可以为绝对路径也可以是相对路径./当前目录,可以省略 ../上一级目录
    -->
        <img src="./assets/image-20230722220249071.png" width="20px" height="20px"> <a href="https://gov.sina.com.cn/"
            target="_self">新浪政务</a> > 正文
        <!-- <h1 style="color: red;">焦点访谈:中国底气 新思想夯实大国粮仓</h1> -->
        <h1>焦点访谈:中国底气 新思想夯实大国粮仓</h1>

        <hr>
        <!-- span是一个没有任何语义的标签 -->
        <!-- a标签:
    href:指定资源的url
    target:指定在何处打开资源链接
      _self:默认值,在当前页面打开
      _blank:在空白页面打开 -->
        <span>2023年07月23日09:10</span> <a href="https://www.cctv.com/" target="_blank">央视网</a>
        <hr>
        <!-- 视频标签video
    src规则视频url
    controls显示播放控件
    width播放器的宽度
    height播放器的高度 -->
        <!-- 音频标签audio
    src规定音频的url
    controls显示播放控件 -->
        <!-- 段落标签p
    文本加粗b strong -->
        <video src="video/1.mp4" controls width="950px"></video>
        <p><b>央视网消息:</b>党的十八大以来,以习近平同志为核心的党中央始终把解决粮食安全问题作为治国理政的头等大事,重农抓粮一系列政策举措有力有效,我国粮食产量站稳1.3万亿斤台阶,实现谷物基本自给、口粮绝对安全。我们把饭碗牢牢端在自己手中,为保障经济社会发展提供了坚实支撑,为应对各种风险挑战赢得了主动。连续八年1.3万亿斤,这个沉甸甸的数据是如何取得的呢?
        </p>
        <!-- 在HTML中无论输入多少个空格,最终只显示一个空格。可以使用空格占位符&nbsp  -->
        <p>人勤春来早,春耕农事忙。立春之后,由南到北,我国春耕春管工作陆续展开,春天的田野处处生机盎然。</p>

        <p id="plast">责任编辑:tom</p>
    </div>
</body>

</html>

两个常见布局标签

  • 布局标签:在实际开发网页中,会大量频繁的使用div和span这两个没有语义的布局标签。
  • <div> <span>
  • 特点
    • div标签
      • 一行只显示一个(独占一行)
      • 宽度默认是父元素的宽度,高度默认由内容撑开
      • 可以设置宽高
    • span标签
      • 一行可以显示多个
      • 宽度和高度默认由内容撑开
      • 不可以设置宽高
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>盒子模型</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            box-sizing: border-box;/* 若没有该属性则为内容的宽高,设置后变成border大小 */
            background-color: aquamarine;
            padding: 20px 20px 20px 20px; /* 内边距:上 右 下 左 */
            border: 10px solid red; /* 边框 宽度 线条类型 颜色 */
            margin: 30px 30px 30px 30px;/* 外边距:上 右 下 左 */
        }
    </style>
</head>
<body>
    <div>
        A A A A A A
    </div>
</body>
</html>

表格标签

标签 描述 属性
<table> 定义表格整体,可以包裹多个<tr> border:规定表格边框宽度 width:规定表格的宽度 cellspacing:规定单元之间的空 间
<tr> 表格的行,可以包裹多个<td>
<td> 表格单元格,包裹内容 如果是表头单元格,可以替换为<th>

表单标签

标签:<form>

表单项:不同类型的input元素,下拉列表,文本域等。

  • <input>:定义表单项,通过type属性控制输入形式。

type类型
  • <select>:定义下拉列表
  • <textarea>:定义文本域

表单属性

  • action:规定当前提交表单时向何处发送表单数据,url。
  • method:规定用于发送表单数据的方式。get、post
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML表单标签</title>
</head>
<body>
    <!-- 
        表单属性:
        action:规定当前提交表单时向何处发送表单数据,url。如果不指定则提交到当前页面
        method:规定用于发送表单数据的方式。get、post 
        get:在url后面拼接表单的数据 ?username=tom&age=12 url长度有限制
        post:在消息体(请求体)中传递,参数大小无限制

    -->
    <form action="" method="get">
        用户名 : <input type="text" name="username">
        年龄 : <input type="text" name="age">
        <input type="submit" value="提交">
    </form>
</body>
</html>

1.2 CSS

什么是CSS?

CSS(Cascading Style Sheet):层叠样式表,用于控制页面的样式(表现)。

CSS引入方式

  • 行内样式:写在标签的style属性中(不推荐)<h1 style = "xxx:xxx ; xxx:xxx;">中国新闻网</h1>
  • 内嵌样式:写在style标签中(可以写在页面任何位置,但通常约定写在head标签中)
1
2
3
4
5
6
<style>
    h1{
        xxx:xxx;
        xxx:xxx;
    }
</style>
  • 外联样式:写在一个单独的.css文件中(需要通过link标签在网页中引入)
1
2
3
4
5
h1{
    xxx:xxx;
    xxx:xxx;
}
<link rel="stylesheet" href="css/news.css">

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>元素的底部,可以改善显示速度
  • 外部脚本:将js代码定义在外部js文件中,然后引入到html页面中
    • 外部js文件中,只包含js代码,不包含<script>标签
    • <script>标签不能自闭合

js基础语法

  • 书写语法

    • 区分大小写:和java一样,变量名函数名以及其他一切都是区分大小写的

    • 每行结尾的分号可有可无

    • 注释:

      • 单行注释://

      • 多行注释:/* */

    • 大括号表示代码块

  • 输出语句

    • 使用windows.alert()写入警告框
    • 使用document.write()写入html输出
    • 使用console.log()写入浏览器控制台
  • 变量

    • 使用var关键字声明变量,var定义的变量是全局变量,可以重复定义
      • ECMAscript6新增let关键字,不允许重复声明,在let代码块内生效
      • ECMAscript6新增constant关键字,用来声明一个只读的常量,一旦声明,常量的值不能改变。
    • JavaScript是一门弱类型语言,变量可以存放不同类型的值
    • 变量名需要如下规则
      • 组成字符可以是任何字母,数字,下划线或者美元符
      • 数字不能开头
      • 建议使用驼峰命名
  • 数据类型

    • JavaScript数据类型分为原始类型和引用类型,使用typeof运算符可以获取数据类型
      • 原始类型
        • number 数字小数NaN
        • string 单引号或者双引号
        • boolean
        • null 对象为空
        • undefined 变量未初始化时默认是undefined
  • 运算符

    • 算数 + - * / ++ –
    • 逻辑
    • 比较 ==会进行类型转换,===不会类型转换
      • 类型转换
        • 字符串转数字:字面值转数字,不是数字返回NaN
        • 其他类型转boolean 0,NaN 空字符串,null 和 underfined转为false
    • 赋值
    • 三元
  • 流程控制语句

    • if..else
    • switch
    • for
    • while
    • do..while

js函数

  • 介绍:函数是被设置为执行特定任务的代码块。
  • 定义:JavaScript通过function关键字进行定义,语法为
1
2
3
function funcitonName(parameter1, parameter2...) {
    //code to be executed
}
  • 注意:
    • 形参不需要定义类型,因为JavaScript是弱类型语言
    • 返回值也不需要定义类型,可以在函数内部直接return返回即可
  • 调用:函数名称(实参列表)
  • 函数第二种定义方式
1
2
3
var functionName = function(parameter1, parmeter2) {
    //rest code
}
注意:函数调用可以传递任意个数的参数。

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 注释对象

dom对象

js事件监听

事件:HTLM事件是发生在HTML上的事情。比如按钮被点击,鼠标移动到元素上,按下键盘按键。

事件监听:JavaScript可以在事件被侦测到时执行代码。

事件绑定:

  • 通过HTML标签中的事件属性进行绑定
  • 通过dom元素进行绑定

2 Vue、ElementUI、Nginx

2.1 vue

什么是vue?

  • vue是一套前端框架,免除原生JavaScript的DOM操作,简化书写。
  • 基于MVVM(model-view-viewmodel)思想,实现数据的双向绑定,将编程的关注点放在数据上。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue快速入门</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-model="message">
        {{message}}
    </div>
</body>
<script>
    //定义vue对象
    new Vue({
        el: "#app", //vue接管的区域
        data: {
            message: "hello vue"
        }
    })
</script>
</html>

Vue常用指令

  • 指令:HTML标签上带有v-前缀的特殊属性,不同指令具有不同的含义。例如v-if,v-for
  • 常见指令:v-bind v-model v-on v-if v-for等等

v-bind

v-bind:为HTML标签绑定属性值,如设置href、css样式等

1
2
<a v-bind:href="url">链接</a>
<a :href="url">链接</a>

v-model

v-model:在表单上创建双向元素绑定

1
<input type="text" v-model="url">

v-on

v-on:为HTML标签绑定事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<input type="button" value="按钮" v-onclick="handle()">
<input type="button" value="按钮" @click="handle()">

<script>
    //定义vue对象
    new Vue({
        el: "#app", //vue接管的区域
        data: {
            message: "hello vue"
        },
        function: {
            handle: function(){
                alert("clicked!")
            }
        }
    })
</script>

v-if

v-if、v-else-if、v-else:条件性的渲染某元素,判定为true时渲染,否则不渲染

1
2
3
4
年龄{{age}},经判定为:
<span v-if="age <= 35">年轻人</span>
<span v-else-if="age > 35 && age < 60">中年人</span>
<span v-else>老年人</span>

v-show

v-show:根据条件展示某元素,区别在于切换的是display属性的值

1
2
年龄{{age}},经判定为:
<span v-show="age <= 35">年轻人</span>

v-for

v-for:列表渲染,遍历容易的元素或者对象的属性

1
2
<div v-for="addr in addrs">{{addr}}</div>
<div v-for="(addr, index) in addrs">{{index + 1}}:{{addr}}</div>

Vue生命周期

  • 生命周期:指一个对象从创建到销毁的整个过程
  • 生命周期的八个阶段,每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)
  • mounted:挂载完成,vue初始化成功,HTML页面渲染成功。(发送到i服务端,加载数据)

vue生命周期

vue各个阶段转换
#### 2.2 Vue组件库 Element

什么是Element?

  • Element:是饿了么团队研发的,一套为开发者、设计师和产品经理准备的基于Vue 2.0的桌面端组件库。
  • 组件:组成网页的部件,例如超链接,按钮,图片,表格,表单,分页条等等。

快速入门

  • 安装ElementUI组件库(在当前工程的目录下),命令行执行指令。

npm install element-ui@2.15.3

  • 引入ElementUI组件库
1
2
3
4
5
//main.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI);
  • 访问官网,复制组件代码,调整

3 Ajax、Axios

3.1 Ajax

什么是Ajax?

  • 概念:Asynchronous JavaScript And XML,异步的JavaScript和XML
  • 作用:
    • 数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据
    • 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:联想搜索,用户名是否可用的校验等等。

同步与异步

3.2 Axios

什么是Axios?

  • 介绍:Axios对原生的Ajax进行了封装,简化书写,快速开发

Axios使用方式

  1. 引入Axios的js文件

<script src="js/axios-0.18.0.js"></script>

  1. 使用Axios发送请求,并获取相应结果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
axios({
    method: "get",
    url: "example.com"
}).then((result)=> {//成功回调函数
    console.log(result.data);
})

axios({
    method: "post",
    url: "example.com",
	data: "id=1"
}).then((result)=> {//成功回调函数
    console.log(result.data);
})

Axios请求方式别名

  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.post(url[,data[,config]])
  • axios.put(url[,data[,config]])
1
2
3
axios.get("example.com").then((result)=> {//成功回调函数
    console.log(result.data);
})

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路由

使用流程:

  • 安装(创建Vue项目时已选择)

npm install vue-router@3.5.1

  • 定义路由表,在index.js下定义
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]

打包

前端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)的概念,通过一小段描述信息来管理项目的构建。


Maven原理

仓库:用于存储资源,管理各种jar包。

  • 本地仓库:自己计算机上的一个目录
  • 中央仓库:由Maven团队维护的全球统一的。仓库地址链接
  • 远程仓库(私服):一般由公司团队搭建的私有仓库

Maven的作用

  • 依赖管理 方便快捷的管理项目依赖的资源(jar包),避免版本冲突的问题

  • 统一项目结构 提供标准,统一的项目结构

    • maven-project
      • src

        • main 实际项目资源

          • java java源代码目录
          • resources 配置文件目录
        • test 测试项目资源

          • java
          • resources
      • pom_xml 项目配置文件

  • 项目构建 标准跨平台(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包,一个项目可以引入多个依赖。
  • 配置:
  1. 在pox.xml中编写<dependencies>标签
  2. <dependencies>标签中使用<dependency>引入坐标
  3. 定义坐标的groupId,artifactId,version
  4. 点击刷新按钮,引入最新加入的坐标

注意:第一次使用依赖可以从链接中检索依赖坐标。

依赖传递

依赖具有传递性。

  • 直接依赖:当前项目直接通过依赖配置建立的依赖关系。
  • 间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源。

Maven依赖传递

排除依赖:指主动断开依赖的资源,被排除的资源无需指定版本。

依赖范围

依赖的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!"

步骤:

  1. 创建Springboot工程,并勾选web开发相关依赖。

  2. 定义HelloController类,添加方法hello,并添加注解。

    1.  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~";
          }
      }
      
  3. 运行测试。

2.3 HTTP协议

HTTP-概述

  • 概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器与服务器之间数据传输的规则。
  • 特点:
    • 基于TCP协议:面向连接,安全。
    • 基于请求-响应模型:一次请求对应一次响应。
    • HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
      • 缺点:多次请求之间不能共享数据。
      • 优点:速度快。

HTTP-请求协议


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 请求响应

请求响应概述


HTTP-请求响应

请求

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

统一响应结果

1
2
3
4
5
6
7
8
9
public class result {
    //响应码,1代表成功,0代表失败
    private Integer code;
    //提示信息
    private String msg;
    //返回的数据
    private Object data;
    //...
}

3.3 分层解耦

三层架构


三层架构
  • Controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
  • service:业务逻辑层,处理具体的业务逻辑。
  • dao:数据访问层(data access object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

分层解耦

  • 内聚:软件中各个模块内部的功能联系。
  • 耦合:衡量软件中各个层/模块之间的依赖、关联程度。
  • 软件设计原则:高内聚低耦合

IOC&DI入门


IOC & DI

步骤:

  1. Service层及Dao层的实现类,交给IOC容器管理,加上注解**@component**
  2. 为controller及service注入运行时,依赖的对象。加上注解**@Autowired**
  3. 运行测试

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SELECT
	字段列表
FROM
	表明列表
WHERE
	条件列表
GROUP BY
	分组字段列表
HAVING
	分组后条件列表
ORDER BY
	排序字段列表
LIMIT
	分页参数

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的区别:

  1. 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。

  2. 判断条件不同: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 多表设计

项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:

  • 一对多(多对一)
  • 多对多
  • 一对一

一对多

一对多关系实现:在数据库表中多的一方,添加字段,来关联一的一方的主键。

问题:部门数据可以直接删除,然而还有部分员工归属于该部门下,此时就出现了数据的不完整、不一致问题。

目前上述的两张表,在数据库层面,并未建立关联,所以是无法保证数据的一致性和完整性的。

此时需要外键约束。

1
2
3
4
5
6
7
8
-- 创建表时指定
create table 表名(
	字段名    数据类型,
	...
	[constraint]   [外键名称]  foreign  key (外键字段名)   references   主表 (字段名)	
);
-- 建完表后,添加外键
alter table  表名  add constraint  外键名称  foreign key (外键字段名) references  主表(字段名);

物理外键

概念:使用 foreign key 定义外键关联另外一张表。

缺点:

  • 影响增、删、改的效率(需要检查外键关系)。

  • 仅用于单节点数据库,不适用与分布式、集群场景。

  • 容易引发数据库的死锁问题,消耗性能。

逻辑外键

  • 概念:在业务层逻辑中,解决外键关联。

  • 通过逻辑外键,就可以很方便的解决上述问题。

一对一

  • 案例: 用户 与 身份证信息 的关系

  • 关系: 一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他字段放在另一张表中,以提升操作效率

  • 实现: 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)

多对多

  • 案例: 学生 与 课程的关系

  • 关系: 一个学生可以选修多门课程,一门课程也可以供多个学生选择

  • 实现: 建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

4.6 多表查询

概述

  • 多表查询: 指从多张表中查询数据

  • 笛卡尔积: 笛卡尔乘积是指在数学中,两个集合(A集合 和 B集合)的所有组合情况。(在多表查询时,需要消除无效的笛卡尔积)

分类

  • 连接查询
    • 内连接:相当于查询A、B交集部分数据
    • 外连接
      • 左外连接:查询左表所有数据(包括两张表交集部分数据)
      • 右外连接:查询右表所有数据(包括两张表交集部分数据)
  • 子查询

image-20230801215108675

内连接

  • 隐式内连接: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;

四大特性

image-20230802165113433

4.8 索引

介绍

索引(index)是帮助数据库高效获取数据的数据结构 。

优缺点:

  • 优点
    • 提高数据查询的效率,降低数据库的IO成本。
    • 通过索引列对数据进行排序,降低数据排序的成本,降低CPU消耗。
  • 缺点
    • 索引会占用存储空间。
    • 索引大大提高了查询效率,同时却也降低了insert、update、delete的效率。

结构

MySQL数据库支持的索引结构有很多,如:Hash索引、B+Tree索引、Full-Text索引等。我们平常所说的索引,如果没有特别指明,都是指默认的 B+Tree 结构组织的索引。

image-20230802171302368

  • 每一个节点,可以存储多个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快速入门

  1. 创建工程,导入驱动jar包。
  2. 注册驱动Class.forName("com.mysql.jdbc.Driver")
  3. 获取连接Connection conn = DriverManger.getConnection(url,username,password)
  4. 定义SQL语句String sql = xxx
  5. 获取执行SQL对象Statement stmt = conn.createStatement()
  6. 执行SQLstmt.executeUpdate(sql)
  7. 处理返回结构
  8. 释放资源stmt.close() conn,close()

6 Mybatis

什么是Mybatis?

image-20230802202037650

  • MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。

  • MyBatis本是 Apache的一个开源项目iBatis, 2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

6.1 MyBatis入门

快速入门

案例:使用Mybatis查询所有用户数据

  1. 准备工作(创建SpringBoot工程、数据库表User、实体类User)
  2. 引入MyBatis的相关依赖,配置MyBatis(数据库连接信息)
  3. 编写SQL语句(注解/XML)

数据库连接池

  • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

  • 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏

image-20230803164632020

连接池优势:

  • 资源重用

  • 提升系统响应速度

  • 避免数据库连接遗漏

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;

接口方法:

1
2
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);

注意:如果mapper接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。

日志输出

  • 可以在application.properties中,打开mybatis的日志,并指定输出到控制台。
1
2
#指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

image-20230804142130064

  • 为什么采用预编译SQL
    • 性能更高 一次编译,多次运行。
    • 更安全(防止SQL注入) SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

image-20230804142305283

  • 参数占位符

image-20230804143215213

新增

  • SQL语句
1
insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values ('songyuanqiao','宋远桥',1,'1.jpg',2,'2012-10-09',2,'2022-10-01 10:00:00','2022-10-01 10:00:00');
  • 接口方法
1
2
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +"values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime},#{updateTime})")
public void insert(Emp emp);
  • 主键返回
1
2
3
@Options(keyProperty = "id", useGeneratedKeys = true)//会自动将生成的主键值,赋值给emp对象的id属性
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +"values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);

更新

  • SQL语句
1
update emp set username = 'songdaxia', name = '宋大侠', gender = 1 , image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2, update_time = '2022-10-01 12:12:12' where id = 19;
  • 接口方法
1
2
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);

查询(根据ID查询)

  • SQL语句
1
select *  from emp where id = 19;
  • 接口方法
1
2
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
  • 数据封装

    • 实体类属性名 和 数据库表查询返回的字段名一致,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语句
1
select *  from emp where name like '%%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01 ' order by update_time desc;
  • 接口方法
1
2
@Select("select * from emp where name like  concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender , LocalDate begin , LocalDate end);

XML映射文件

规范:

  • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。

  • XML映射文件的namespace属性为Mapper接口全限定名一致。

  • XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

image-20230804190940802

6.3 MyBatis动态SQL

什么是动态SQL?

定义:随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。

<if>

<if>:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。`

<where>:where 元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND 或OR.

<set>:动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)

<foreach>

1
2
3
4
5
<delete id="deleteByIds">
    delete from emp where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">#{id}
    </foreach>
</delete>
  • collection:集合名称

  • item:集合遍历出来的元素/项

  • separator:每一次遍历使用的分隔符

  • open:遍历开始前拼接的片段

  • close:遍历结束后拼接的片段

<sql><include>

1
2
3
4
<sql id="commonSelect">
    select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
<include refid="commonSelect"/>

提升sql语句的复用性。

三、SSM

1 Web后端案例基础-增删改查(SpringBootWeb案例)

1.1 准备工作

需求

  • 部门管理

    • 查询部门列表

    • 删除部门

    • 新增部门

    • 修改部门

  • 员工管理

    • 查询员工列表(分页、条件)
    • 删除员工
    • 新增员工
    • 修改员工

环境搭建

  • 准备数据库表(dept、emp)

  • 创建springboot工程,引入对应的起步依赖(web、mybatis、mysql驱动、lombok)

  • 配置文件application.properties中引入mybatis的配置信息,准备对应的实体类

  • 准备对应的Mapper、Service(接口、实现类)、Controller基础结构

image-20230806163204609

开发规范

案例基于当前最为主流的前后端分离模式进行开发。

image-20230806173047837

  • 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 部门管理

查询部门

image-20230806174813632

删除部门

image-20230806183016889

新增部门

image-20230806184030215

路径抽取

image-20230806185527184

一个完整的请求路径,应该是类上的 @RequestMapping 的value属性 + 方法上的 @RequestMapping的value属性。

1.3 员工管理

分页查询

image-20230807125240592

分页插件PageHelper

image-20230807131838728

条件分页查询

image-20230807133149512

删除员工

image-20230807145326872

新增员工

image-20230807162705238

文件上传

  • 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。

  • 文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

image-20230807165053121

本地存储

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@RestController
public class UploadController {
    @PostMapping("/upload")
    public Result upload(MultipartFile image) throws IOException {
        //获取原始文件名
        String originalFilename = image.getOriginalFilename();
        //构建新的文件名
        String newFileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
        //将文件保存在服务器端 E:/images/ 目录下       
        image.transferTo(new File("E:/images/"+newFileName));
        return Result.success();
    }
}

在SpringBoot中,文件上传,默认单个文件允许最大大小为 1M。如果需要上传大文件,可以进行如下配置:

1
2
3
4
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB

云存储

阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。

image-20230807172650172

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@RestController
public class UploadController {
    @Autowired
    private AliOSSUtils aliOSSUtils;
    @PostMapping(/upload)
    public Result upload(MultipartFile image) throws IOException {
    	String url = aliOSSUtils.upload(image); //调用阿里云OSS工具类,将上传上来的文件存入阿里云
		return Result.success(url); //将图片上传完成后的url返回,用于浏览器回显展示
    }
}

查询回显

image-20230807185350052

更新员工信息

image-20230807190313910

1.4 配置文件

参数配置化

image-20230807192256886

  • @Value 注解通常用于外部配置的属性注入,具体用法为: @Value("${配置文件中的key}")

yml配置文件

SpringBoot提供了多种属性配置方式

  • application.properties
1
2
server.port=8080
server.address=127.0.0.1
  • application.yml
1
2
3
server:
   port:  8080
   address: 127.0.0.1
  • application.yaml
1
2
3
server:
   port:  8080
   address: 127.0.0.1

yml

基本语法

  • 大小写敏感

  • 数值前边必须有空格,作为分隔符

  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)

  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略

数据格式

对象/map集合:

1
2
3
4
user:
   name: zhangsan
   age: 18
   password: 123456

数组/List/Set集合:

1
2
3
4
hobby:
  - java
  - game
  - sport

@ConfigurationProperties

image-20230807194400731

@ConfigurationProperties 与 @Value

相同点:

  • 都是用来注入外部配置的属性的。

不同点:

  • @Value注解只能一个一个的进行外部属性的注入。

  • @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中。

2 Web后端案例基础-登录认证

2.1 登录功能

基础登录功能

image-20230808170755815

2.2 登录校验

登录校验概述

image-20230808172512783

登录标记:会话技术

统一拦截:过滤器Filter、拦截器Interceptor

会话技术

  • 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
  • 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
  • 会话跟踪方案:
    • 客户端会话跟踪技术:Cookie
    • 服务端会话跟踪技术:Session
    • 令牌技术

会话跟踪方案一:Cookie

image-20230808173937061

  • 优点:HTTP协议中支持的技术

  • 缺点:

    • 移动端APP无法使用Cookie
    • 不安全,用户可以自己禁用Cookie
    • Cookie不能跨域

image-20230808174048471

跨域区分三个维度:协议、IP/域名、端口

会话跟踪方案二:Session

image-20230808174837405

  • 优点:存储在服务端,安全

  • 缺点:

    • 服务器集群环境下无法直接使用Session
    • Cookie的缺点

会话跟踪方案三:令牌技术

image-20230808182403157

  • 优点:

    • 支持PC端、移动端
    • 解决集群环境下的认证问题
    • 减轻服务器端存储压力
  • 缺点:需要自己实现

JWT令牌

  • 全称:JSON Web Token (https://jwt.io/)

  • 定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

  • 组成:

    • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
    • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
    • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

image-20230808183004825

JWT-生成

  • 引入依赖:
1
2
3
4
5
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
  • 生成JWT
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Test
public void genJwt(){
    Map<String,Object> claims = new HashMap<>();
    claims.put(id,1);
    claims.put(username,Tom);
    String jwt = Jwts.builder()
        .setClaims(claims) //自定义内容(载荷)
        .signWith(SignatureAlgorithm.HS256, itheima) //签名算法
        .setExpiration(new Date(System.currentTimeMillis() + 12*3600*1000)) //有效期
        .compact();
    System.out.println(jwt);
}
  • 校验JWT
1
2
3
4
5
6
7
8
@Test
public void testParseJWT() {
    Claims claims = Jwts.parser()
            .setSigningKey("secret内容")
            .parseClaimsJws("JWT令牌")
            .getBody();
    System.out.println(claims);
}

JWT令牌-登录后下发

  • 引入JWT令牌操作工具类。

  • 登录完成后,调用工具类生成JWT令牌,并返回。

过滤器Filter

  • 概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。

  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。

  • 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

image-20230808194602168

过滤器快速入门

  1. 定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法。
  2. 配置Filter:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件

image-20230808195114923

image-20230808195143772

过滤器详解

执行流程

image-20230808200129024

拦截路径

  • Filter 可以根据需求,配置不同的拦截资源路径:
拦截路径 urlPatterns值 含义
拦截具体路径 /login 只有访问 /login 路径时,才会被拦截
目录拦截 /emps/* 访问/emps下的所有资源,都会被拦截
拦截所有 /* 访问所有资源,都会被拦截

过滤器链

image-20230808204257104

  • 介绍:一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。
  • 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。

过滤器登录校验-Filter

image-20230808204800685

拦截器Interceptor

  • 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。

  • 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

image-20230809211811640

拦截器快速入门

  1. 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。

  2. 注册拦截器

image-20230809212052448

image-20230809212121490

拦截器详解

  • 拦截器可以根据需求,配置不同的拦截路径:

image-20230809213341833

拦截路径 含义 举例
/* 一级路径 能匹配/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

image-20230809213825281

Filter和Interceptor区别

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。

  • 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

2.3 异常处理

程序开发过程中不可避免的会遇到异常现象,出现异常时,默认返回的结果不符合规范

全局异常处理器

image-20230809215330805

image-20230809215429978

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对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。

image-20230810153315995

AOP快速入门

案例:统计各个业务层方法执行耗时

  • 导入依赖:
1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 编写AOP程序,针对于特定方法根据业务需要进行编程
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Component
@Aspect
public class TimeAspect {
    @Around("execution(* com.learning.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        Object object = proceedingJoinPoint.proceed(); //调用原始方法运行
        long end = System.currentTimeMillis();
        log.info(proceedingJoinPoint.getSignature()+"执行耗时: {}ms", end - begin);
        return object;
    }
}

场景:

  • 记录操作日志
  • 权限控制
  • 事务管理

优势:

  • 代码无侵入
  • 减少重复代码
  • 提高开发效率
  • 维护方便

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)

1
2
3
//定义LOG
@Retention(RetentionPolicy.RUNTIME);//该注解运行时有效
@Target(ElementType.METHOD)//该注解作用在方法上

连接点

在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 注解来进行配置作用域:

1
2
3
4
5
@Scope("prototype")
@RestController
@RequestMapping("/depts")
	public class DeptController {
}

注意事项:

  • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)。
  • prototype的bean,每一次使用该bean的时候都会创建一个新的实例。
  • 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。

第三方Bean

如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,就需要用到 @Bean注解。

1
2
3
4
5
6
7
@SpringBootApplication
public class SpringbootWebConfig2Application {
    @Bean //将方法返回值交给IOC容器管理,成为IOC容器的bean对象
    public SAXReader saxReader(){
    return new SAXReader();
	}
}

若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。

1
2
3
4
5
6
7
@Configuration
public class CommonConfig {
    @Bean
    public SAXReader saxReader(){
        return new SAXReader();
    }
}

注意事项:

  • 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
  • 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。

5.3 SpringBoot管理

起步依赖

原理就是maven的依赖传递。

自动配置

SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。

自动配置原理

  • 方案一:@ComponentScan 组件扫描
1
2
3
4
5
@ComponentScan({"com.example","com.itheima"})//若显式声明则会覆盖隐式声明,需要加上默认包
@SpringBootApplication
public class SpringbootWebConfig2Application {
    xxx;
}
  • 方案二:@Import 导入。使用@Import导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:
    • 导入 普通类
    • 导入 配置类
    • 导入 ImportSelector 接口实现类
    • @EnableXxxx注解,封装@Import注解
1
2
3
4
5
@Import({TokenParser.class, HeaderConfig.class})
@SpringBootApplication
public class SpringbootWebConfig2Application {
    xxx;
}

@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直接使用即可。

步骤:

  1. 创建 aliyun-oss-spring-boot-starter 模块
  2. 创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中引入该模块
  3. 在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports

Javaweb总结:

image-20230814211410230

updatedupdated2023-08-142023-08-14