JasonsGong.github.io/posts/60684.html
2024-06-14 22:00:25 +08:00

1591 lines
492 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>SpringBoot入门教程 | The Blog</title><meta name="author" content="Jason"><meta name="copyright" content="Jason"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="尚硅谷雷丰阳的SpringBoot零基础入门教程 本视频笔记地址https:&#x2F;&#x2F;yuque.com&#x2F;atguigu&#x2F;springboot 本视频源码地址https:&#x2F;&#x2F;gitee.com&#x2F;leifengyang&#x2F;springboot2 Spring官网: https:&#x2F;&#x2F;spring.io&#x2F; SpringBoot2的环境要求 一.SpringBoot2核心技术-基础入门1.Spring能做">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringBoot入门教程">
<meta property="og:url" content="https://qingling.icu/posts/60684.html">
<meta property="og:site_name" content="The Blog">
<meta property="og:description" content="尚硅谷雷丰阳的SpringBoot零基础入门教程 本视频笔记地址https:&#x2F;&#x2F;yuque.com&#x2F;atguigu&#x2F;springboot 本视频源码地址https:&#x2F;&#x2F;gitee.com&#x2F;leifengyang&#x2F;springboot2 Spring官网: https:&#x2F;&#x2F;spring.io&#x2F; SpringBoot2的环境要求 一.SpringBoot2核心技术-基础入门1.Spring能做">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://qingling.icu/img/10.png">
<meta property="article:published_time" content="2023-07-31T01:10:33.000Z">
<meta property="article:modified_time" content="2024-05-10T05:31:11.642Z">
<meta property="article:author" content="Jason">
<meta property="article:tag" content="SpringBoot">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://qingling.icu/img/10.png"><link rel="shortcut icon" href="/img/%E5%9B%BE%E6%A0%87.png"><link rel="canonical" href="https://qingling.icu/posts/60684.html"><link rel="preconnect" href="//fastly.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="/cdn/icon/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="/cdn/css/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="/cdn/css/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: {"path":"/search.xml","preload":true,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容:${query}","hits_stats":"共找到 ${hits} 篇文章"}},
translate: undefined,
noticeOutdate: undefined,
highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":400},
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: true,
post: true
},
runtime: '天',
dateSuffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'mediumZoom',
Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#006650","bgDark":"#006650","position":"top-center"},
source: {
justifiedGallery: {
js: 'https://fastly.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
css: 'https://fastly.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
}
},
isPhotoFigcaption: false,
islazyload: false,
isAnchor: true,
percent: {
toc: true,
rightside: false,
},
autoDarkmode: true
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: 'SpringBoot入门教程',
isPost: true,
isHome: false,
isHighlightShrink: false,
isToc: true,
postUpdate: '2024-05-10 13:31:11'
}</script><noscript><style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style></noscript><script>(win=>{
win.saveToLocal = {
set: function setWithExpiry(key, value, ttl) {
if (ttl === 0) return
const now = new Date()
const expiryDay = ttl * 86400000
const item = {
value: value,
expiry: now.getTime() + expiryDay,
}
localStorage.setItem(key, JSON.stringify(item))
},
get: function getWithExpiry(key) {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = new Date()
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
win.getScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
})
win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onerror = reject
link.onload = link.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
link.onload = link.onreadystatechange = null
resolve()
}
document.head.appendChild(link)
})
win.activateDarkMode = function () {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
win.activateLightMode = function () {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
const t = saveToLocal.get('theme')
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified
if (t === undefined) {
if (isLightMode) activateLightMode()
else if (isDarkMode) activateDarkMode()
else if (isNotSpecified || hasNoSupport) {
const now = new Date()
const hour = now.getHours()
const isNight = hour <= 8 || hour >= 22
isNight ? activateDarkMode() : activateLightMode()
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
if (saveToLocal.get('theme') === undefined) {
e.matches ? activateDarkMode() : activateLightMode()
}
})
} else if (t === 'light') activateLightMode()
else activateDarkMode()
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
})(window)</script><script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script><script type="text/javascript" src ="/js/welcome.js" ></script><script src="/js/sweetalert.js"></script><link rel="stylesheet" href="/css/sweetalert.css"><!-- hexo injector head_end start --><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css" media="print" onload="this.media='all'"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/loading.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">60</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">39</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">10</div></a></div><br/><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw fas fa-stream"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/"><i class="fa-fw fas fa-list"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="The Blog"><img class="site-icon" src="/img/logo.png"/><span class="site-name">The Blog</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw fas fa-stream"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/"><i class="fa-fw fas fa-list"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">SpringBoot入门教程</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-07-31T01:10:33.000Z" title="发表于 2023-07-31 09:10:33">2023-07-31</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-05-10T05:31:11.642Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%90%8E%E7%AB%AF/">后端</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">21.6k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>100分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="SpringBoot入门教程"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div><article class="post-content" id="article-container"><p>尚硅谷雷丰阳的SpringBoot零基础入门教程</p>
<p><strong>本视频笔记地址:</strong><a target="_blank" rel="noopener" href="https://yuque.com/atguigu/springboot">https://yuque.com/atguigu/springboot</a></p>
<p><strong>本视频源码地址:</strong><a target="_blank" rel="noopener" href="https://gitee.com/leifengyang/springboot2">https://gitee.com/leifengyang/springboot2</a></p>
<p><strong>Spring官网:</strong> <a target="_blank" rel="noopener" href="https://spring.io/">https://spring.io/</a></p>
<p>SpringBoot2的环境要求</p>
<p><img src="/pictures/image-20230620092919922.png" alt="image-20230620092919922"></p>
<h1 id="一-SpringBoot2核心技术-基础入门"><a href="#一-SpringBoot2核心技术-基础入门" class="headerlink" title="一.SpringBoot2核心技术-基础入门"></a>一.SpringBoot2核心技术-基础入门</h1><h2 id="1-Spring能做什么"><a href="#1-Spring能做什么" class="headerlink" title="1.Spring能做什么"></a>1.Spring能做什么</h2><p>这里的Spring指的是整个Spring生态</p>
<p><img src="/pictures/image-20230620093420150.png" alt="image-20230620093420150"></p>
<p><strong>微服务 响应式编程 分布式 WEB开发 无服务开发 事件驱动 批处理</strong></p>
<h2 id="2-SpringBoot"><a href="#2-SpringBoot" class="headerlink" title="2.SpringBoot"></a>2.SpringBoot</h2><p>Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.</p>
<p>能快速创建出生产级别的Spring应用</p>
<p>SpringBoot是整合Spring技术栈的一站式框架</p>
<p>SpringBoot是简化Spring技术栈的快速开发脚手架</p>
<h3 id="2-1-SpringBoot的优点"><a href="#2-1-SpringBoot的优点" class="headerlink" title="2.1 SpringBoot的优点"></a>2.1 SpringBoot的优点</h3><p>● Create stand-alone Spring applications<br> ○ 创建独立Spring应用<br>● Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)<br> ○ 内嵌web服务器<br>● Provide opinionated starter dependencies to simplify your build configuration<br> ○ 自动starter依赖简化构建配置<br>● Automatically configure Spring and 3rd party libraries whenever possible<br> ○ 自动配置Spring以及第三方功能<br>● Provide production-ready features such as metrics, health checks, and externalized configuration<br> ○ 提供生产级别的监控、健康检查及外部化配置<br>● Absolutely no code generation and no requirement for XML configuration<br> ○ 无代码生成、无需编写XML</p>
<h3 id="2-2、SpringBoot缺点"><a href="#2-2、SpringBoot缺点" class="headerlink" title="2.2、SpringBoot缺点"></a>2.2、SpringBoot缺点</h3><ul>
<li>人称版本帝,迭代快,需要时刻关注变化(说明社区活跃,也是个优点)</li>
<li>封装太深,内部原理复杂,不容易精通</li>
</ul>
<h3 id="2-3-官方文档"><a href="#2-3-官方文档" class="headerlink" title="2.3 官方文档"></a>2.3 官方文档</h3><p>进入官网 找到SpringBoot 点击Reference Doc进入官方文档</p>
<p><img src="/pictures/image-20230620101533445.png" alt="image-20230620101533445"></p>
<h2 id="3-SpringBoot入门"><a href="#3-SpringBoot入门" class="headerlink" title="3.SpringBoot入门"></a>3.SpringBoot入门</h2><h3 id="1-系统的要求"><a href="#1-系统的要求" class="headerlink" title="1.系统的要求"></a>1.系统的要求</h3><ul>
<li><a target="_blank" rel="noopener" href="https://www.java.com/">Java 8</a> &amp; 兼容java14 .</li>
<li>Maven 3.3+</li>
<li>idea 2019.1.2</li>
</ul>
<p>**Maven的配置教程: **</p>
<p><a href="https://qingling.icu/posts/26768.html">Maven配置文件settings.xml | The Blog (qingling.icu)</a></p>
<p><a href="https://qingling.icu/posts/63333.html">开发环境的搭建 | The Blog (qingling.icu)</a></p>
<h3 id="2-HelloWorld"><a href="#2-HelloWorld" class="headerlink" title="2.HelloWorld"></a>2.HelloWorld</h3><p><strong>需求:浏览发送&#x2F;hello请求响应 HelloSpring Boot 2</strong> </p>
<p>1创建maven工程</p>
<p><img src="/pictures/image-20230725160846882.png" alt="image-20230725160846882"></p>
<p>2.引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.4.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!-- WEB场景的启动器 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>3.创建主程序</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/7/25</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span> <span class="comment">//标注这是一个SpringBoot应用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"> SpringApplication.run(MainApplication.class,args);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>4.编写Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/7/25</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">handle01</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;Hello,Spring Boot2&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<img src="/pictures/image-20230725162201612.png" alt="image-20230725162201612" style="zoom:150%;" />
<h3 id="3-简化配置"><a href="#3-简化配置" class="headerlink" title="3.简化配置"></a>3.简化配置</h3><p>官网地址:<a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/application-properties.html#appendix.application-properties">https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/application-properties.html#appendix.application-properties</a></p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server.port</span>=<span class="string">8888</span></span><br></pre></td></tr></table></figure>
<h3 id="4-简化部署"><a href="#4-简化部署" class="headerlink" title="4.简化部署"></a>4.简化部署</h3><p>通过在pom.xml文件中插入这个插件,可以直接将项目打成jar包简化部署</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230725163026091.png" alt="image-20230725163026091"></p>
<p>可以直接使用cmd切换到target目录下使用<code>java -jar </code>命令运行jar包</p>
<p><img src="/pictures/image-20230725163212347.png" alt="image-20230725163212347"></p>
<p><strong>注意点</strong></p>
<p>去掉cmd的快速编辑模式不去掉启动的时候点击屏幕会停止</p>
<p><img src="/pictures/image-20230725164124574.png" alt="image-20230725164124574"></p>
<h2 id="4-了解自动装配原理"><a href="#4-了解自动装配原理" class="headerlink" title="4.了解自动装配原理"></a>4.了解自动装配原理</h2><h3 id="4-1-依赖管理"><a href="#4-1-依赖管理" class="headerlink" title="4.1 依赖管理"></a>4.1 依赖管理</h3><h4 id="1-SpringBoot的自动版本仲裁机制"><a href="#1-SpringBoot的自动版本仲裁机制" class="headerlink" title="1.SpringBoot的自动版本仲裁机制"></a><strong>1.SpringBoot的自动版本仲裁机制</strong></h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 项目的继承的父项目--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.4.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 父项目继承的父项目--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--几乎声明了开发中常用依赖的版本号--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.4.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230725165414051.png" alt="image-20230725165414051"></p>
<p><strong>自定义mysql版本驱动</strong></p>
<p>在父依赖中mysql是8版本的</p>
<p><img src="/pictures/image-20230725170329032.png" alt="image-20230725170329032"></p>
<p>可以在pom.xml中通过自定义properties修改版本</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!--重写mysql的版本号--&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">mysql.version</span>&gt;</span>5.1.43<span class="tag">&lt;/<span class="name">mysql.version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230725170257030.png" alt="image-20230725170257030"></p>
<h4 id="2-Starters场景启动器"><a href="#2-Starters场景启动器" class="headerlink" title="2.Starters场景启动器"></a>2.Starters场景启动器</h4><p>官网: <a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/using.html#using.build-systems.starters">https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/using.html#using.build-systems.starters</a></p>
<p><strong><code>spring-boot-starter-*</code>起头的starter为官方提供的starter<code>*-spring-boot-starter</code>为第三方提供的starter</strong></p>
<p>常见的Starter</p>
<p><img src="/pictures/image-20230725171130925.png" alt="image-20230725171130925"></p>
<p>以引入<code>spring-boot-starter-web</code>为例引入该starter它会帮我们引入以下的其它依赖</p>
<p><img src="/pictures/image-20230725171550618.png" alt="image-20230725171550618"></p>
<h3 id="4-2-自动配置"><a href="#4-2-自动配置" class="headerlink" title="4.2 自动配置"></a>4.2 自动配置</h3><ul>
<li><p><strong>自动配置Tomcat</strong></p>
<ol>
<li><p>引入依赖</p>
<p><img src="/pictures/image-20230725172719608.png" alt="image-20230725172719608"></p>
</li>
<li><p>配置Tomcat</p>
</li>
</ol>
</li>
<li><p><strong>自动配置SpringMvc</strong></p>
<ol>
<li><p>引入springMvc全套组件</p>
</li>
<li><p>自动配置好springMvc的常用组件字符编码文件上传解析器dispatcherServlet等</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"> <span class="comment">//返回ioc容器</span></span><br><span class="line"> <span class="type">ConfigurableApplicationContext</span> <span class="variable">run</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line"> <span class="comment">//获取容器里面组件的名字</span></span><br><span class="line"> String[] beanDefinitionNames = run.getBeanDefinitionNames();</span><br><span class="line"> <span class="keyword">for</span> (String beanDefinitionName : beanDefinitionNames) &#123;</span><br><span class="line"> <span class="comment">//打印容器内的组件</span></span><br><span class="line"> System.out.println(beanDefinitionName);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230725172834666.png" alt="image-20230725172834666"></p>
</li>
</ol>
</li>
<li><p><strong>默认的包结构</strong></p>
<p>主程序所在的包以及其的子包都可以被扫描到,无需配置包扫描</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">com</span><br><span class="line"> +- example</span><br><span class="line"> +- myapplication</span><br><span class="line"> +- MyApplication.java #主程序</span><br><span class="line"> |</span><br><span class="line"> +- customer</span><br><span class="line"> | +- Customer.java</span><br><span class="line"> | +- CustomerController.java</span><br><span class="line"> | +- CustomerService.java</span><br><span class="line"> | +- CustomerRepository.java</span><br><span class="line"> |</span><br><span class="line"> +- order</span><br><span class="line"> +- Order.java</span><br><span class="line"> +- OrderController.java</span><br><span class="line"> +- OrderService.java</span><br><span class="line"> +- OrderRepository.java</span><br></pre></td></tr></table></figure>
<p>如果需要扫描的文件在主程序的上级目录,我们也想扫描到它,我们需要扩大一下包的扫描范围</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication(scanBasePackages = &quot;com.atguigu&quot;)</span></span><br><span class="line">或者</span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.atguigu&quot;)</span></span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>各种配置拥有默认值</strong></p>
<p><img src="/pictures/image-20230725174350129.png" alt="image-20230725174350129"></p>
</li>
<li><p><strong>按需加载所有的自动配置项</strong></p>
<p>spingboot的所有配置存在于下面的这个依赖中</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-autoconfigure<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.4.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230725175010683.png" alt="image-20230725175010683"></p>
</li>
</ul>
<h3 id="4-3-容器功能"><a href="#4-3-容器功能" class="headerlink" title="4.3 容器功能"></a>4.3 容器功能</h3><h4 id="1-组件添加"><a href="#1-组件添加" class="headerlink" title="1.组件添加"></a>1.组件添加</h4><h5 id="1-1-Configuration"><a href="#1-1-Configuration" class="headerlink" title="1.1 @Configuration"></a>1.1 @Configuration</h5><ul>
<li><p>基本使用</p>
</li>
<li><p><strong>Full模式与Lite模式</strong></p>
</li>
<li><ul>
<li>示例</li>
<li>最佳实战</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>配置 类组件之间无依赖关系用Lite模式加速容器启动过程减少判断</li>
<li>配置类组件之间有依赖关系方法会被调用得到之前单实例组件用Full模式</li>
</ul>
</li>
</ul>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1、配置类里面使用<span class="doctag">@Bean</span>标注在方法上给容器注册组件,默认也是单实例的</span></span><br><span class="line"><span class="comment"> * 2、配置类本身也是组件</span></span><br><span class="line"><span class="comment"> * 3、proxyBeanMethods代理bean的方法</span></span><br><span class="line"><span class="comment"> * Full(proxyBeanMethods = true)、【保证每个<span class="doctag">@Bean</span>方法被调用多少次返回的组件都是单实例的】</span></span><br><span class="line"><span class="comment"> * Lite(proxyBeanMethods = false)【每个<span class="doctag">@Bean</span>方法被调用多少次返回的组件都是新创建的】</span></span><br><span class="line"><span class="comment"> * 组件依赖必须使用Full模式默认。其他默认是否Lite模式</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span> <span class="comment">//告诉SpringBoot这是一个配置类 == 配置文件</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfig</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Bean</span> <span class="comment">//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值就是组件在容器中的实例</span></span><br><span class="line"> <span class="keyword">public</span> User <span class="title function_">user01</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="type">User</span> <span class="variable">zhangsan</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">18</span>);</span><br><span class="line"> <span class="comment">//user组件依赖了Pet组件</span></span><br><span class="line"> zhangsan.setPet(tomcatPet());</span><br><span class="line"> <span class="keyword">return</span> zhangsan;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Bean(&quot;tom&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> Pet <span class="title function_">tomcatPet</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Pet</span>(<span class="string">&quot;tomcat&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootConfiguration</span></span><br><span class="line"><span class="meta">@EnableAutoConfiguration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.atguigu.boot&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainApplication</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"> <span class="comment">//1、返回我们IOC容器</span></span><br><span class="line"> <span class="type">ConfigurableApplicationContext</span> <span class="variable">run</span> <span class="operator">=</span> SpringApplication.run(MainApplication.class, args);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//2、查看容器里面的组件</span></span><br><span class="line"> String[] names = run.getBeanDefinitionNames();</span><br><span class="line"> <span class="keyword">for</span> (String name : names) &#123;</span><br><span class="line"> System.out.println(name);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//3、从容器中获取组件</span></span><br><span class="line"></span><br><span class="line"> <span class="type">Pet</span> <span class="variable">tom01</span> <span class="operator">=</span> run.getBean(<span class="string">&quot;tom&quot;</span>, Pet.class);</span><br><span class="line"></span><br><span class="line"> <span class="type">Pet</span> <span class="variable">tom02</span> <span class="operator">=</span> run.getBean(<span class="string">&quot;tom&quot;</span>, Pet.class);</span><br><span class="line"></span><br><span class="line"> System.out.println(<span class="string">&quot;组件:&quot;</span>+(tom01 == tom02));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892</span></span><br><span class="line"> <span class="type">MyConfig</span> <span class="variable">bean</span> <span class="operator">=</span> run.getBean(MyConfig.class);</span><br><span class="line"> System.out.println(bean);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。</span></span><br><span class="line"> <span class="comment">//保持组件单实例</span></span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> bean.user01();</span><br><span class="line"> <span class="type">User</span> <span class="variable">user1</span> <span class="operator">=</span> bean.user01();</span><br><span class="line"> System.out.println(user == user1);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="type">User</span> <span class="variable">user01</span> <span class="operator">=</span> run.getBean(<span class="string">&quot;user01&quot;</span>, User.class);</span><br><span class="line"> <span class="type">Pet</span> <span class="variable">tom</span> <span class="operator">=</span> run.getBean(<span class="string">&quot;tom&quot;</span>, Pet.class);</span><br><span class="line"></span><br><span class="line"> System.out.println(<span class="string">&quot;用户的宠物:&quot;</span>+(user01.getPet() == tom));</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="1-2-Bean-Component-Controller-Service-Repository"><a href="#1-2-Bean-Component-Controller-Service-Repository" class="headerlink" title="1.2 @Bean @Component @Controller @Service @Repository"></a>1.2 @Bean @Component @Controller @Service @Repository</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//默认是单实例的</span></span><br><span class="line"><span class="meta">@Bean</span><span class="comment">//给容器中添加组件以方法名作为组件的id(组件名),返回类型就是组件类型,返回的值,就是组件在容器中的实例,@Bean(&quot;user&quot;) 是自定义组件名为user</span></span><br><span class="line"><span class="keyword">public</span> User <span class="title function_">user01</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&quot;Tom&quot;</span>,<span class="number">100</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="1-3-ComponentScan-Import"><a href="#1-3-ComponentScan-Import" class="headerlink" title="1.3 @ComponentScan @Import"></a>1.3 @ComponentScan @Import</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * @Import(&#123;User.class, DBHelper.class&#125;) 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Import(&#123;User.class, DBHelper.class&#125;)</span></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfig</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="1-4-Conditional-条件装配满足Conditional指定的条件则进行组件注入"><a href="#1-4-Conditional-条件装配满足Conditional指定的条件则进行组件注入" class="headerlink" title="1.4 @Conditional 条件装配满足Conditional指定的条件则进行组件注入"></a>1.4 @Conditional 条件装配满足Conditional指定的条件则进行组件注入</h5><p><img src="/pictures/image-20230802141422751.png" alt="image-20230802141422751"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//放在类上面,条件成立,这个类下面的所有配置生效,放在方法上面,条件成立,这个方法下的配置才会成立</span></span><br><span class="line"><span class="meta">@ConditionalOnBean(name = &quot;tom&quot;)</span> <span class="comment">//存在一个id为tom的组件的时候才会生效</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(name = &quot;tom&quot;)</span></span><br></pre></td></tr></table></figure>
<h4 id="2-原生配置文件的引入"><a href="#2-原生配置文件的引入" class="headerlink" title="2.原生配置文件的引入"></a>2.原生配置文件的引入</h4><h5 id="2-1、-ImportResource"><a href="#2-1、-ImportResource" class="headerlink" title="2.1、@ImportResource"></a>2.1、@ImportResource</h5><p>beans.xml*</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"> <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;haha&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.atguigu.boot.bean.User&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;zhangsan&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;18&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"> <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;hehe&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.atguigu.boot.bean.Pet&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;tomcat&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在java类中红使用@ImportResource(“classpath:beans.xml”)导入上面的配置文件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ImportResource(&quot;classpath:beans.xml&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfig</span> &#123;&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-配置绑定"><a href="#3-配置绑定" class="headerlink" title="3.配置绑定"></a>3.配置绑定</h4><h5 id="3-1-ConfigurationProperties"><a href="#3-1-ConfigurationProperties" class="headerlink" title="3.1 @ConfigurationProperties"></a>3.1 @ConfigurationProperties</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 只有在容器中的组件才会拥有SpringBoot提供的强大功能</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span> <span class="comment">//或者在配置类上添加@EnableConfigurationProperties(Car.class)注解,不使用@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;mycar&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Car</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String brand;</span><br><span class="line"> <span class="keyword">private</span> Integer price;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getBrand</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> brand;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBrand</span><span class="params">(String brand)</span> &#123;</span><br><span class="line"> <span class="built_in">this</span>.brand = brand;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Integer <span class="title function_">getPrice</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> price;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setPrice</span><span class="params">(Integer price)</span> &#123;</span><br><span class="line"> <span class="built_in">this</span>.price = price;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;Car&#123;&quot;</span> +</span><br><span class="line"> <span class="string">&quot;brand=&#x27;&quot;</span> + brand + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line"> <span class="string">&quot;, price=&quot;</span> + price +</span><br><span class="line"> <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置文件中的值</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mycar.brand</span>=<span class="string">BYD</span></span><br><span class="line"><span class="attr">mycar.price</span>=<span class="string">120000</span></span><br></pre></td></tr></table></figure>
<p>编写测试的controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> Car car;</span><br><span class="line"><span class="meta">@RequestMapping(&quot;/car&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Car <span class="title function_">ggetCar</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> car;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<img src="/pictures/image-20230802153951542.png" alt="image-20230802153951542" style="zoom: 150%;" />
<h3 id="4-4-自动配置原理入门"><a href="#4-4-自动配置原理入门" class="headerlink" title="4.4 自动配置原理入门"></a>4.4 自动配置原理入门</h3><h4 id="1-引导加载自动配置类"><a href="#1-引导加载自动配置类" class="headerlink" title="1.引导加载自动配置类"></a>1.引导加载自动配置类</h4><p><strong>@SpringBootApplication</strong></p>
<p><img src="/pictures/image-20230802155222746.png" alt="image-20230802155222746"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootConfiguration</span> <span class="comment">//代表当前是一个配置类</span></span><br><span class="line"><span class="meta">@EnableAutoConfiguration</span> </span><br><span class="line"><span class="meta">@ComponentScan(excludeFilters = &#123; @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),</span></span><br><span class="line"><span class="meta"> @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) &#125;)</span><span class="comment">//指定扫描那些spring注解</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> SpringBootApplication&#123;&#125;</span><br></pre></td></tr></table></figure>
<p><strong>@EnableAutoConfiguration</strong> </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@AutoConfigurationPackage</span></span><br><span class="line"><span class="meta">@Import(AutoConfigurationImportSelector.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> EnableAutoConfiguration &#123;&#125;</span><br></pre></td></tr></table></figure>
<p><strong>@AutoConfigurationPackage</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Import(AutoConfigurationPackages.Registrar.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> AutoConfigurationPackage &#123;&#125;</span><br></pre></td></tr></table></figure>
<p><strong>Registrar.class</strong></p>
<p><img src="/pictures/image-20230802160618158.png" alt="image-20230802160618158"></p>
<p><strong>利用Registrar给容器中导入com.atguigu.boot主程序所在的包包下的一系列组件</strong></p>
<p><img src="/pictures/image-20230802161004735.png" alt="image-20230802161004735"></p>
<p><strong>@Import(AutoConfigurationImportSelector.class)</strong> </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件</span><br><span class="line"><span class="number">2</span>、调用List&lt;String&gt; configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类</span><br><span class="line"><span class="number">3</span>、利用工厂加载 Map&lt;String, List&lt;String&gt;&gt; <span class="title function_">loadSpringFactories</span><span class="params">(<span class="meta">@Nullable</span> ClassLoader classLoader)</span>;得到所有的组件</span><br><span class="line"><span class="number">4</span>、从META-INF/spring.factories位置来加载一个文件。</span><br><span class="line"> 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件</span><br><span class="line"> spring-boot-autoconfigure-<span class="number">2.3</span><span class="number">.4</span>.RELEASE.jar包里面也有META-INF/spring.factories</span><br></pre></td></tr></table></figure>
<p><strong>AutoConfigurationImportSelector.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> String[] selectImports(AnnotationMetadata annotationMetadata) &#123;</span><br><span class="line"> <span class="keyword">if</span> (!isEnabled(annotationMetadata)) &#123;</span><br><span class="line"> <span class="keyword">return</span> NO_IMPORTS;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="type">AutoConfigurationEntry</span> <span class="variable">autoConfigurationEntry</span> <span class="operator">=</span> getAutoConfigurationEntry(annotationMetadata);</span><br><span class="line"> <span class="keyword">return</span> StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>getAutoConfigurationEntry()方法</strong></p>
<p>利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> AutoConfigurationEntry <span class="title function_">getAutoConfigurationEntry</span><span class="params">(AnnotationMetadata annotationMetadata)</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (!isEnabled(annotationMetadata)) &#123;</span><br><span class="line"> <span class="keyword">return</span> EMPTY_ENTRY;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="type">AnnotationAttributes</span> <span class="variable">attributes</span> <span class="operator">=</span> getAttributes(annotationMetadata);</span><br><span class="line"> List&lt;String&gt; configurations = getCandidateConfigurations(annotationMetadata, attributes);</span><br><span class="line"> configurations = removeDuplicates(configurations);</span><br><span class="line"> Set&lt;String&gt; exclusions = getExclusions(annotationMetadata, attributes);</span><br><span class="line"> checkExcludedClasses(configurations, exclusions);</span><br><span class="line"> configurations.removeAll(exclusions);</span><br><span class="line"> configurations = getConfigurationClassFilter().filter(configurations);</span><br><span class="line"> fireAutoConfigurationImportEvents(configurations, exclusions);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AutoConfigurationEntry</span>(configurations, exclusions);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>**getCandidateConfigurations()**获取所有候选的配置</p>
<p>调用List<String> configurations &#x3D; getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类</p>
<p><img src="/pictures/image-20230802162236987.png" alt="image-20230802162236987"></p>
<p><strong>loadSpringFactories()</strong></p>
<p>利用工厂加载 Map&lt;String, List<String>&gt; loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> Map&lt;String, List&lt;String&gt;&gt; <span class="title function_">loadSpringFactories</span><span class="params">(<span class="meta">@Nullable</span> ClassLoader classLoader)</span> &#123;</span><br><span class="line"> MultiValueMap&lt;String, String&gt; result = (MultiValueMap)cache.get(classLoader);</span><br><span class="line"> <span class="keyword">if</span> (result != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> Enumeration&lt;URL&gt; urls = classLoader != <span class="literal">null</span> ? classLoader.getResources(<span class="string">&quot;META-INF/spring.factories&quot;</span>) : ClassLoader.getSystemResources(<span class="string">&quot;META-INF/spring.factories&quot;</span>);</span><br><span class="line"> MultiValueMap&lt;String, String&gt; result = <span class="keyword">new</span> <span class="title class_">LinkedMultiValueMap</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(urls.hasMoreElements()) &#123;</span><br><span class="line"> <span class="type">URL</span> <span class="variable">url</span> <span class="operator">=</span> (URL)urls.nextElement();</span><br><span class="line"> <span class="type">UrlResource</span> <span class="variable">resource</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UrlResource</span>(url);</span><br><span class="line"> <span class="type">Properties</span> <span class="variable">properties</span> <span class="operator">=</span> PropertiesLoaderUtils.loadProperties(resource);</span><br><span class="line"> <span class="type">Iterator</span> <span class="variable">var6</span> <span class="operator">=</span> properties.entrySet().iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(var6.hasNext()) &#123;</span><br><span class="line"> Map.Entry&lt;?, ?&gt; entry = (Map.Entry)var6.next();</span><br><span class="line"> <span class="type">String</span> <span class="variable">factoryTypeName</span> <span class="operator">=</span> ((String)entry.getKey()).trim();</span><br><span class="line"> String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());</span><br><span class="line"> <span class="type">int</span> <span class="variable">var10</span> <span class="operator">=</span> var9.length;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var11</span> <span class="operator">=</span> <span class="number">0</span>; var11 &lt; var10; ++var11) &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">factoryImplementationName</span> <span class="operator">=</span> var9[var11];</span><br><span class="line"> result.add(factoryTypeName, factoryImplementationName.trim());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> cache.put(classLoader, result);</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException var13) &#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Unable to load factories from location [META-INF/spring.factories]&quot;</span>, var13);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>从META-INF&#x2F;spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF&#x2F;spring.factories位置的文件,spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF&#x2F;spring.factories</strong></p>
<p><img src="/pictures/image-20230802163429366.png" alt="image-20230802163429366"></p>
<p><strong>在spring.factories这个配置文件中写死了springBoot一启动就要给容器加载的所有配置类一共127个</strong></p>
<p><img src="/pictures/image-20230802163708198.png" alt="image-20230802163708198"></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br></pre></td><td class="code"><pre><span class="line"># Initializers</span><br><span class="line">org.springframework.context.ApplicationContextInitializer=\</span><br><span class="line">org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\</span><br><span class="line">org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener</span><br><span class="line"></span><br><span class="line"># Application Listeners</span><br><span class="line">org.springframework.context.ApplicationListener=\</span><br><span class="line">org.springframework.boot.autoconfigure.BackgroundPreinitializer</span><br><span class="line"></span><br><span class="line"># Auto Configuration Import Listeners</span><br><span class="line">org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\</span><br><span class="line">org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener</span><br><span class="line"></span><br><span class="line"># Auto Configuration Import Filters</span><br><span class="line">org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\</span><br><span class="line">org.springframework.boot.autoconfigure.condition.OnBeanCondition,\</span><br><span class="line">org.springframework.boot.autoconfigure.condition.OnClassCondition,\</span><br><span class="line">org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition</span><br><span class="line"></span><br><span class="line"># Auto Configure</span><br><span class="line">org.springframework.boot.autoconfigure.EnableAutoConfiguration=\</span><br><span class="line">org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\</span><br><span class="line">org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration</span><br><span class="line"></span><br><span class="line"># Failure analyzers</span><br><span class="line">org.springframework.boot.diagnostics.FailureAnalyzer=\</span><br><span class="line">org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\</span><br><span class="line">org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer</span><br><span class="line"></span><br><span class="line"># Template availability providers</span><br><span class="line">org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\</span><br><span class="line">org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\</span><br><span class="line">org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\</span><br><span class="line">org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\</span><br><span class="line">org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\</span><br><span class="line">org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider</span><br></pre></td></tr></table></figure>
<h4 id="2-按需开启自动配置项"><a href="#2-按需开启自动配置项" class="headerlink" title="2.按需开启自动配置项"></a>2.按需开启自动配置项</h4><p> 虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration,按照条件装配规则(@Conditional),最终会按需配置,比如下面的配置是否生效还要通过@Conditional的条件判断。</p>
<p><strong>简单的一句话:启动的时候加载所有,使用的时候按照条件(@Conditional)进行装配</strong></p>
<p><img src="/pictures/image-20230802164424689.png" alt="image-20230802164424689"></p>
<h4 id="3-修改默认配置"><a href="#3-修改默认配置" class="headerlink" title="3.修改默认配置"></a>3.修改默认配置</h4><p> 相当于当我们在容器中注入了类型为MultipartResolver但是id不为multipartResolver的组件的时候会帮我们规范一下命名命名为multipartResolver。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@ConditionalOnBean(MultipartResolver.class)</span> <span class="comment">//存在MultipartResolver类型的组件</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)</span><span class="comment">//不存在以multipartResolver为id的组件</span></span><br><span class="line"><span class="keyword">public</span> MultipartResolver <span class="title function_">multipartResolver</span><span class="params">(MultipartResolver resolver)</span> &#123;</span><br><span class="line"> <span class="comment">// Detect if the user has created a MultipartResolver but named it incorrectly</span></span><br><span class="line"> <span class="keyword">return</span> resolver;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean</span> <span class="comment">//没有的话就将这个配置注入到容器中</span></span><br><span class="line"><span class="keyword">public</span> CharacterEncodingFilter <span class="title function_">characterEncodingFilter</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="type">CharacterEncodingFilter</span> <span class="variable">filter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">OrderedCharacterEncodingFilter</span>();</span><br><span class="line"> filter.setEncoding(<span class="built_in">this</span>.properties.getCharset().name());</span><br><span class="line"> filter.setForceRequestEncoding(<span class="built_in">this</span>.properties.shouldForce(Encoding.Type.REQUEST));</span><br><span class="line"> filter.setForceResponseEncoding(<span class="built_in">this</span>.properties.shouldForce(Encoding.Type.RESPONSE));</span><br><span class="line"> <span class="keyword">return</span> filter;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>总结:</p>
<ul>
<li><p>SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration</p>
</li>
<li><p>每个自动配置类按照条件进行生效默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定</p>
</li>
<li><p>生效的配置类就会给容器中装配很多组件</p>
</li>
<li><p>只要容器中有这些组件,相当于这些功能就有了</p>
</li>
<li><p>定制化配置</p>
</li>
<li><ul>
<li>用户直接自己@Bean替换底层的组件</li>
<li>用户去看这个组件是获取的配置文件什么值就去修改。</li>
</ul>
</li>
</ul>
<p>xxxxxAutoConfiguration —&gt; 组件 —&gt; xxxxProperties取值 —-&gt; application.properties</p>
<h4 id="3-4-最佳实践"><a href="#3-4-最佳实践" class="headerlink" title="3.4.最佳实践"></a>3.4.最佳实践</h4><ul>
<li><p>引入场景依赖</p>
</li>
<li><ul>
<li><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter">https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter</a></li>
</ul>
</li>
<li><p>查看自动配置了哪些(选做)</p>
</li>
<li><ul>
<li>自己分析,引入场景对应的自动配置一般都生效了</li>
<li>配置文件中<strong>debug&#x3D;true开启自动配置报告</strong>。Negative不生效\Positive生效</li>
</ul>
</li>
<li><p>是否需要修改</p>
</li>
<li><ul>
<li>参照文档修改配置项</li>
</ul>
</li>
<li><ul>
<li><ul>
<li><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties">https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties</a></li>
<li>自己分析。xxxxProperties绑定了配置文件的哪些。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li>自定义加入或者替换组件</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>@Bean、@Component。。。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li>自定义器 <strong>XXXXXCustomizer</strong></li>
</ul>
</li>
</ul>
<h3 id="4-5-简化开发"><a href="#4-5-简化开发" class="headerlink" title="4.5 简化开发"></a>4.5 简化开发</h3><h4 id="1-Lombok"><a href="#1-Lombok" class="headerlink" title="1.Lombok"></a>1.Lombok</h4><p>引入依赖(使用前需要安装插件)</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@NoArgsConstructor</span> <span class="comment">//无参构造器</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span> <span class="comment">//有参构造器</span></span><br><span class="line"><span class="meta">@Data</span> <span class="comment">//getter和setter方法</span></span><br><span class="line"><span class="meta">@ToString</span> </span><br><span class="line"><span class="meta">@EqualsAndHashCode</span></span><br></pre></td></tr></table></figure>
<h4 id="2-简化日志开发"><a href="#2-简化日志开发" class="headerlink" title="2.简化日志开发"></a>2.简化日志开发</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br></pre></td></tr></table></figure>
<h3 id="3-dev-tools"><a href="#3-dev-tools" class="headerlink" title="3.dev-tools"></a>3.dev-tools</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-devtools<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>项目或者页面修改以后Ctrl+F9</p>
<h3 id="4-Spring-Initailizr项目初始化向导"><a href="#4-Spring-Initailizr项目初始化向导" class="headerlink" title="4.Spring Initailizr项目初始化向导"></a>4.Spring Initailizr项目初始化向导</h3><p><img src="/pictures/image-20230803103657995.png" alt="image-20230803103657995"></p>
<p><img src="/pictures/image-20230803104032505.png" alt="image-20230803104032505"></p>
<p><img src="/pictures/image-20230803104655578.png" alt="image-20230803104655578"></p>
<h1 id=""><a href="#" class="headerlink" title=""></a></h1><h1 id="二-SpringBoot2核心技术-核心功能"><a href="#二-SpringBoot2核心技术-核心功能" class="headerlink" title="二.SpringBoot2核心技术-核心功能"></a>二.SpringBoot2核心技术-核心功能</h1><p><img src="/pictures/image-20230803104919434.png" alt="image-20230803104919434"></p>
<h2 id="一-配置文件"><a href="#一-配置文件" class="headerlink" title="一.配置文件"></a>一.配置文件</h2><h3 id="1、文件类型"><a href="#1、文件类型" class="headerlink" title="1、文件类型"></a>1、文件类型</h3><h4 id="1-1、properties"><a href="#1-1、properties" class="headerlink" title="1.1、properties"></a>1.1、properties</h4><p>同以前的properties用法</p>
<h4 id="1-2、yaml"><a href="#1-2、yaml" class="headerlink" title="1.2、yaml"></a>1.2、yaml</h4><h5 id="1-2-1、简介"><a href="#1-2-1、简介" class="headerlink" title="1.2.1、简介"></a>1.2.1、简介</h5><p>YAML 是 “YAML Aint Markup Language”YAML 不是一种标记语言的递归缩写。在开发的这种语言时YAML 的意思其实是”Yet Another Markup Language”仍是一种标记语言</p>
<p>非常适合用来做以数据为中心的配置文件</p>
<h5 id="1-2-2、基本语法"><a href="#1-2-2、基本语法" class="headerlink" title="1.2.2、基本语法"></a>1.2.2、基本语法</h5><ul>
<li>key: valuekv之间有空格</li>
<li>大小写敏感</li>
<li>使用缩进表示层级关系</li>
<li>缩进不允许使用tab只允许空格</li>
<li>缩进的空格数不重要,只要相同层级的元素左对齐即可</li>
<li>#’表示注释</li>
<li>字符串无需加引号,如果要加,’’与””表示字符串内容 会被 转义&#x2F;不转义</li>
</ul>
<h5 id="1-2-3、数据类型"><a href="#1-2-3、数据类型" class="headerlink" title="1.2.3、数据类型"></a>1.2.3、数据类型</h5><ul>
<li>字面量单个的、不可再分的值。date、boolean、string、number、null</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">k:</span> <span class="string">v</span></span><br></pre></td></tr></table></figure>
<ul>
<li>对象键值对的集合。map、hash、set、object</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">行内写法:</span> <span class="attr">k:</span> &#123;<span class="string">k1:v1</span>,<span class="string">k2:v2</span>,<span class="string">k3:v3</span>&#125;</span><br><span class="line"><span class="comment">#或</span></span><br><span class="line"><span class="attr">k:</span> </span><br><span class="line"> <span class="attr">k1:</span> <span class="string">v1</span></span><br><span class="line"> <span class="attr">k2:</span> <span class="string">v2</span></span><br><span class="line"> <span class="attr">k3:</span> <span class="string">v3</span></span><br></pre></td></tr></table></figure>
<ul>
<li>数组一组按次序排列的值。array、list、queue</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">行内写法:</span> <span class="attr">k:</span> [<span class="string">v1</span>,<span class="string">v2</span>,<span class="string">v3</span>]</span><br><span class="line"><span class="comment">#或者</span></span><br><span class="line"><span class="attr">k:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">v1</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">v2</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">v3</span></span><br></pre></td></tr></table></figure>
<h5 id="1-2-4、示例"><a href="#1-2-4、示例" class="headerlink" title="1.2.4、示例"></a>1.2.4、示例</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix=&quot;person&quot;)</span><span class="comment">//和以person开头的配置文件绑定</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> String userName;</span><br><span class="line"> <span class="keyword">private</span> Boolean boss;</span><br><span class="line"> <span class="keyword">private</span> Date birth;</span><br><span class="line"> <span class="keyword">private</span> Integer age;</span><br><span class="line"> <span class="keyword">private</span> Pet pet;</span><br><span class="line"> <span class="keyword">private</span> String[] interests;</span><br><span class="line"> <span class="keyword">private</span> List&lt;String&gt; animal;</span><br><span class="line"> <span class="keyword">private</span> Map&lt;String, Object&gt; score;</span><br><span class="line"> <span class="keyword">private</span> Set&lt;Double&gt; salarys;</span><br><span class="line"> <span class="keyword">private</span> Map&lt;String, List&lt;Pet&gt;&gt; allPets;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pet</span> &#123;</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> Double weight;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># yaml表示以上对象</span></span><br><span class="line"><span class="attr">person:</span></span><br><span class="line"><span class="comment"># 单引号会将 \n作为字符串输出 双引号会将\n 作为换行输出</span></span><br><span class="line"><span class="comment"># 双引号不会转义,单引号会转义</span></span><br><span class="line"> <span class="attr">userName:</span> <span class="string">zhangsan</span></span><br><span class="line"> <span class="attr">boss:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">birth:</span> <span class="number">2019</span><span class="string">/12/12</span> <span class="number">20</span><span class="string">:12:33</span></span><br><span class="line"> <span class="attr">age:</span> <span class="number">18</span></span><br><span class="line"> <span class="attr">pet:</span> </span><br><span class="line"> <span class="attr">name:</span> <span class="string">tomcat</span></span><br><span class="line"> <span class="attr">weight:</span> <span class="number">23.4</span></span><br><span class="line"> <span class="attr">interests:</span> [<span class="string">篮球</span>,<span class="string">游泳</span>]</span><br><span class="line"> <span class="attr">animal:</span> </span><br><span class="line"> <span class="bullet">-</span> <span class="string">jerry</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">mario</span></span><br><span class="line"> <span class="attr">score:</span></span><br><span class="line"> <span class="attr">english:</span> </span><br><span class="line"> <span class="attr">first:</span> <span class="number">30</span></span><br><span class="line"> <span class="attr">second:</span> <span class="number">40</span></span><br><span class="line"> <span class="attr">third:</span> <span class="number">50</span></span><br><span class="line"> <span class="attr">math:</span> [<span class="number">131</span>,<span class="number">140</span>,<span class="number">148</span>]</span><br><span class="line"> <span class="attr">chinese:</span> &#123;<span class="attr">first:</span> <span class="number">128</span>,<span class="attr">second:</span> <span class="number">136</span>&#125;</span><br><span class="line"> <span class="attr">salarys:</span> [<span class="number">3999</span>,<span class="number">4999.98</span>,<span class="number">5999.99</span>]</span><br><span class="line"> <span class="attr">allPets:</span></span><br><span class="line"> <span class="attr">sick:</span></span><br><span class="line"> <span class="bullet">-</span> &#123;<span class="attr">name:</span> <span class="string">tom</span>&#125;</span><br><span class="line"> <span class="bullet">-</span> &#123;<span class="attr">name:</span> <span class="string">jerry</span>,<span class="attr">weight:</span> <span class="number">47</span>&#125;</span><br><span class="line"> <span class="attr">health:</span> [&#123;<span class="attr">name:</span> <span class="string">mario</span>,<span class="attr">weight:</span> <span class="number">47</span>&#125;]</span><br></pre></td></tr></table></figure>
<h3 id="2、配置提示"><a href="#2、配置提示" class="headerlink" title="2、配置提示"></a>2、配置提示</h3><p>自定义的类和配置文件绑定一般没有提示</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--打包的时候去除这个配置提示器--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">excludes</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">exclude</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclude</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">excludes</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="二-Web开发"><a href="#二-Web开发" class="headerlink" title="二.Web开发"></a>二.Web开发</h2><p><img src="/pictures/image-20230803134143859.png" alt="image-20230803134143859"></p>
<h3 id="1-简单的功能分析"><a href="#1-简单的功能分析" class="headerlink" title="1.简单的功能分析"></a>1.简单的功能分析</h3><h4 id="1-1-静态资源访问"><a href="#1-1-静态资源访问" class="headerlink" title="1.1 静态资源访问"></a>1.1 静态资源访问</h4><h5 id="1-静态资源目录"><a href="#1-静态资源目录" class="headerlink" title="1.静态资源目录"></a>1.静态资源目录</h5><p>只要静态资源放在类路径下: <code>/static</code> (or <code>/public</code> or <code>/resources</code> or <code>/META-INF/resources</code></p>
<p>访问 当前项目根路径&#x2F; + 静态资源名 </p>
<p>原理: 静态映射&#x2F;**</p>
<p>请求进来先去找Controller看能不能处理不能处理的所有请求又都交给<strong>静态资源处理器</strong>,静态资源也找不到则响应<strong>404页面</strong></p>
<p><strong>改变默认的静态资源路径</strong></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">resources:</span></span><br><span class="line"> <span class="attr">static-locations:</span> [<span class="string">classpath:/haha/</span>] <span class="comment">#静态资源的目录</span></span><br></pre></td></tr></table></figure>
<h5 id="2-静态资源访问前缀"><a href="#2-静态资源访问前缀" class="headerlink" title="2.静态资源访问前缀"></a>2.静态资源访问前缀</h5><p>默认无前缀</p>
<p>默认的访问路径: <code>localhost:8080/xxx.png</code></p>
<p>设置访问前缀之后: <code>localhost:8080/res/xxx.png</code> (文件在目录中的位置没有改变只是访问的时候加上了res这一层路径)</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">mvc:</span></span><br><span class="line"> <span class="attr">static-path-pattern:</span> <span class="string">/res/**</span></span><br></pre></td></tr></table></figure>
<p>当前项目 + static-path-pattern + 静态资源名 &#x3D; 静态资源文件夹下找</p>
<h5 id="3-webjar"><a href="#3-webjar" class="headerlink" title="3.webjar"></a>3.webjar</h5><p>自动映射 &#x2F;<a target="_blank" rel="noopener" href="http://localhost:8080/webjars/jquery/3.5.1/jquery.js">webjars</a>&#x2F;**</p>
<p><a target="_blank" rel="noopener" href="https://www.webjars.org/">https://www.webjars.org/</a></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.webjars<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jquery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.5.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>访问地址:<a target="_blank" rel="noopener" href="http://localhost:8080/webjars/jquery/3.5.1/jquery.js">http://localhost:8080/webjars/jquery/3.5.1/jquery.js</a> 后面地址要按照依赖里面的包路径</p>
<h4 id="1-2-欢迎页支持"><a href="#1-2-欢迎页支持" class="headerlink" title="1.2 欢迎页支持"></a>1.2 欢迎页支持</h4><ul>
<li><p>静态资源路径下 index.html</p>
</li>
<li><ul>
<li>可以配置静态资源路径</li>
<li>但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问</li>
</ul>
</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"><span class="comment"># mvc:</span></span><br><span class="line"><span class="comment"># static-path-pattern: /res/** 这个会导致welcome page功能失效</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">resources:</span></span><br><span class="line"> <span class="attr">static-locations:</span> [<span class="string">classpath:/haha/</span>]</span><br></pre></td></tr></table></figure>
<ul>
<li>controller能处理&#x2F;index</li>
</ul>
<h4 id="1-3-自定义-Favicon"><a href="#1-3-自定义-Favicon" class="headerlink" title="1.3 自定义 Favicon"></a>1.3 自定义 <code>Favicon</code></h4><p>favicon.ico 放在静态资源目录下即可(名称为favicon.ico)</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"><span class="comment"># mvc:</span></span><br><span class="line"><span class="comment"># static-path-pattern: /res/** 这个会导致 Favicon 功能失效</span></span><br></pre></td></tr></table></figure>
<h4 id="1-4-静态资源配置原理"><a href="#1-4-静态资源配置原理" class="headerlink" title="1.4 静态资源配置原理"></a>1.4 静态资源配置原理</h4><p><strong>1.SpringMvc的自动配置类WebMvcAutoConfiguration</strong></p>
<p><img src="/pictures/image-20230803165113057.png" alt="image-20230803165113057"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123; Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class &#125;)</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)</span></span><br><span class="line"><span class="meta">@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)</span></span><br><span class="line"><span class="meta">@AutoConfigureAfter(&#123; DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,</span></span><br><span class="line"><span class="meta"> ValidationAutoConfiguration.class &#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebMvcAutoConfiguration</span> &#123;&#125;</span><br></pre></td></tr></table></figure>
<p><strong>2.SpringMvc给容器中配置的组件</strong></p>
<p><img src="/pictures/image-20230803180257123.png" alt="image-20230803180257123"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@Import(EnableWebMvcConfiguration.class)</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(&#123; WebMvcProperties.class, ResourceProperties.class &#125;)</span></span><br><span class="line"><span class="meta">@Order(0)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">WebMvcAutoConfigurationAdapter</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;&#125;</span><br></pre></td></tr></table></figure>
<p><strong>3.绑定的配置</strong></p>
<p><strong>@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })</strong></p>
<p>WebMvcProperties.class</p>
<p><img src="/pictures/image-20230803180600438.png" alt="image-20230803180600438"></p>
<p>ResourceProperties.class </p>
<p><img src="/pictures/image-20230803180633611.png" alt="image-20230803180633611"></p>
<h3 id="2-请求参数处理与数据响应"><a href="#2-请求参数处理与数据响应" class="headerlink" title="2.请求参数处理与数据响应"></a>2.请求参数处理与数据响应</h3><h4 id="2-1、请求映射"><a href="#2-1、请求映射" class="headerlink" title="2.1、请求映射"></a>2.1、请求映射</h4><h5 id="1、rest使用与原理"><a href="#1、rest使用与原理" class="headerlink" title="1、rest使用与原理"></a>1、rest使用与原理</h5><ul>
<li><p>@xxxMapping</p>
</li>
<li><p>Rest风格支持<em>使用<strong>HTTP</strong>请求方式动词来表示对资源的操作</em></p>
</li>
<li><ul>
<li>以前:&#x2F;getUser 获取用户 &#x2F;deleteUser 删除用户 &#x2F;editUser 修改用户 &#x2F;saveUser 保存用户</li>
<li>现在: &#x2F;user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户</li>
<li>核心FilterHiddenHttpMethodFilter</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>用法: 表单method&#x3D;post隐藏域 _method&#x3D;put</li>
<li>SpringBoot中手动开启</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#开启使用rest风格的注解</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">mvc:</span></span><br><span class="line"> <span class="attr">hiddenmethod:</span></span><br><span class="line"> <span class="attr">filter:</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--发送put或者delete请求--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/user&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;delete&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_m&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;delete&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&quot;REST-DELETE 提交&quot;</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/user&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;PUT&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&quot;REST-PUT 提交&quot;</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><ul>
<li>扩展如何把_method 这个名字换成我们自己喜欢的。</li>
</ul>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(value = &quot;/user&quot;,method = RequestMethod.GET)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getUser</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;GET-张三&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/user&quot;,method = RequestMethod.POST)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">saveUser</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;POST-张三&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/user&quot;,method = RequestMethod.PUT)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">putUser</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;PUT-张三&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/user&quot;,method = RequestMethod.DELETE)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">deleteUser</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;DELETE-张三&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//自定义filter</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> HiddenHttpMethodFilter <span class="title function_">hiddenHttpMethodFilter</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="type">HiddenHttpMethodFilter</span> <span class="variable">methodFilter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HiddenHttpMethodFilter</span>();</span><br><span class="line"> methodFilter.setMethodParam(<span class="string">&quot;_m&quot;</span>);</span><br><span class="line"> <span class="keyword">return</span> methodFilter;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Rest原理表单提交要使用REST的时候</p>
<ul>
<li><p>表单提交会带上_method&#x3D;PUT</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--发送put或者delete请求--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/user&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;delete&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_m&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;delete&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&quot;REST-DELETE 提交&quot;</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/user&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;_method&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">value</span>=<span class="string">&quot;PUT&quot;</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">value</span>=<span class="string">&quot;REST-PUT 提交&quot;</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>请求过来被HiddenHttpMethodFilter拦截</p>
<p>WebMvcAutoConfiguration</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(prefix = &quot;spring.mvc.hiddenmethod.filter&quot;, name = &quot;enabled&quot;, matchIfMissing = false)</span></span><br><span class="line"><span class="keyword">public</span> OrderedHiddenHttpMethodFilter <span class="title function_">hiddenHttpMethodFilter</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">OrderedHiddenHttpMethodFilter</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><ul>
<li>请求是否正常并且是POST</li>
</ul>
</li>
<li><ul>
<li><ul>
<li><p>获取到_method的值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doFilterInternal</span><span class="params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span></span><br><span class="line"> <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">requestToUse</span> <span class="operator">=</span> request;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="string">&quot;POST&quot;</span>.equals(request.getMethod()) &amp;&amp; request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">paramValue</span> <span class="operator">=</span> request.getParameter(<span class="built_in">this</span>.methodParam);</span><br><span class="line"> <span class="keyword">if</span> (StringUtils.hasLength(paramValue)) &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> paramValue.toUpperCase(Locale.ENGLISH);</span><br><span class="line"> <span class="keyword">if</span> (ALLOWED_METHODS.contains(method)) &#123;</span><br><span class="line"> requestToUse = <span class="keyword">new</span> <span class="title class_">HttpMethodRequestWrapper</span>(request, method);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> filterChain.doFilter(requestToUse, response);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>兼容以下请求PUT.DELETE.PATCH</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> List&lt;String&gt; ALLOWED_METHODS =</span><br><span class="line"> Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),</span><br><span class="line"> HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));</span><br></pre></td></tr></table></figure>
</li>
<li><p>原生requestpost包装模式requesWrapper重写了getMethod方法返回的是传入的值</p>
</li>
<li><p>过滤器链放行的时候用wrapper,以后的方法调用getMethod是调用requesWrapper的</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>Tips</strong>:</p>
<p>Rest使用客户端工具如PostMan直接发送put、delete等方式请求无需Filter,不需要转换</p>
<p><strong>扩展点:</strong></p>
<p>如何将<code>&lt;input name=&quot;_method&quot; type=&quot;hidden&quot; value=&quot;delete&quot;/&gt;</code>中的name值_method改为自定义的值?</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span> <span class="comment">//组件中没有依赖关系设置成false直接放</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span>&#123;</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> HiddenHttpMethodFilter <span class="title function_">hiddenHttpMethodFilter</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="type">HiddenHttpMethodFilter</span> <span class="variable">methodFilter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HiddenHttpMethodFilter</span>();</span><br><span class="line"> methodFilter.setMethodParam(<span class="string">&quot;_m&quot;</span>); <span class="comment">//将name=&quot;_method&quot;改成name=&quot;_m&quot;</span></span><br><span class="line"> <span class="keyword">return</span> methodFilter;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="2、请求映射原理"><a href="#2、请求映射原理" class="headerlink" title="2、请求映射原理"></a>2、请求映射原理</h5><p><strong>DispatcherServlet 继承 FrameworkServlet</strong> </p>
<p><strong>FrameworkServlet 继承 HttpServletBean</strong></p>
<p><strong>FrameworkServlet 重写了doGet和doPost方法</strong></p>
<p><img src="/pictures/image-20230809133846464.png" alt="image-20230809133846464"></p>
<p><strong>DispatcherServlet的doDispatch方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doDispatch</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">processedRequest</span> <span class="operator">=</span> request;</span><br><span class="line"> <span class="type">HandlerExecutionChain</span> <span class="variable">mappedHandler</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">multipartRequestParsed</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">WebAsyncManager</span> <span class="variable">asyncManager</span> <span class="operator">=</span> WebAsyncUtils.getAsyncManager(request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="type">ModelAndView</span> <span class="variable">mv</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="type">Exception</span> <span class="variable">dispatchException</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> processedRequest = checkMultipart(request);</span><br><span class="line"> multipartRequestParsed = (processedRequest != request);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Determine handler for the current request.</span></span><br><span class="line"> <span class="comment">//找到请求使用那个hander(contrller)处理</span></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * getHandler()方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> mappedHandler = getHandler(processedRequest);</span><br><span class="line"> <span class="keyword">if</span> (mappedHandler == <span class="literal">null</span>) &#123;</span><br><span class="line"> noHandlerFound(processedRequest, response);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Determine handler adapter for the current request.</span></span><br><span class="line"> <span class="type">HandlerAdapter</span> <span class="variable">ha</span> <span class="operator">=</span> getHandlerAdapter(mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Process last-modified header, if supported by the handler.</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> request.getMethod();</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isGet</span> <span class="operator">=</span> <span class="string">&quot;GET&quot;</span>.equals(method);</span><br><span class="line"> <span class="keyword">if</span> (isGet || <span class="string">&quot;HEAD&quot;</span>.equals(method)) &#123;</span><br><span class="line"> <span class="type">long</span> <span class="variable">lastModified</span> <span class="operator">=</span> ha.getLastModified(request, mappedHandler.getHandler());</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">new</span> <span class="title class_">ServletWebRequest</span>(request, response).checkNotModified(lastModified) &amp;&amp; isGet) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!mappedHandler.applyPreHandle(processedRequest, response)) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Actually invoke the handler.</span></span><br><span class="line"> mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> applyDefaultViewName(processedRequest, mv);</span><br><span class="line"> mappedHandler.applyPostHandle(processedRequest, response, mv);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> dispatchException = ex;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line"> <span class="comment">// As of 4.3, we&#x27;re processing Errors thrown from handler methods as well,</span></span><br><span class="line"> <span class="comment">// making them available for @ExceptionHandler methods and other scenarios.</span></span><br><span class="line"> dispatchException = <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler dispatch failed&quot;</span>, err);</span><br><span class="line"> &#125;</span><br><span class="line"> processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> triggerAfterCompletion(processedRequest, response, mappedHandler, ex);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line"> triggerAfterCompletion(processedRequest, response, mappedHandler,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler processing failed&quot;</span>, err));</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">finally</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line"> <span class="comment">// Instead of postHandle and afterCompletion</span></span><br><span class="line"> <span class="keyword">if</span> (mappedHandler != <span class="literal">null</span>) &#123;</span><br><span class="line"> mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="comment">// Clean up any resources used by a multipart request.</span></span><br><span class="line"> <span class="keyword">if</span> (multipartRequestParsed) &#123;</span><br><span class="line"> cleanupMultipart(processedRequest);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>getHandler()方法</strong> 遍历查找可以处理请求的方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">protected</span> HandlerExecutionChain <span class="title function_">getHandler</span><span class="params">(HttpServletRequest request)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.handlerMappings != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">for</span> (HandlerMapping mapping : <span class="built_in">this</span>.handlerMappings) &#123;</span><br><span class="line"> <span class="type">HandlerExecutionChain</span> <span class="variable">handler</span> <span class="operator">=</span> mapping.getHandler(request);</span><br><span class="line"> <span class="keyword">if</span> (handler != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> handler;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>**HandlerMapping ** 处理器映射</p>
<p>默认有5个HandlerMapping</p>
<p><img src="/pictures/image-20230809150915450.png" alt="image-20230809150915450"></p>
<p><strong>RequestMappingHandlerMapping</strong>:保存了所有@RequestMapping 和handler的映射规则</p>
<p><img src="/pictures/image-20230809151427867.png" alt="image-20230809151427867"></p>
<p>所有的请求映射都在HandlerMapping中</p>
<ul>
<li><p>SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 访问 &#x2F;能访问到index.html</p>
</li>
<li><p>SpringBoot自动配置了默认的 RequestMappingHandlerMapping</p>
</li>
<li><p>请求进来挨个尝试所有的HandlerMapping看是否有请求信息</p>
</li>
<li><ul>
<li>如果有就找到这个请求对应的handler</li>
<li>如果没有就是下一个 HandlerMapping</li>
</ul>
</li>
<li><p>我们需要一些自定义的映射处理,我们也可以自己给容器中放<strong>HandlerMapping</strong> 自定义 <strong>HandlerMapping</strong></p>
</li>
</ul>
<h4 id="2-2、普通参数与基本注解"><a href="#2-2、普通参数与基本注解" class="headerlink" title="2.2、普通参数与基本注解"></a>2.2、普通参数与基本注解</h4><h5 id="1-注解"><a href="#1-注解" class="headerlink" title="1.注解"></a>1.注解</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@PathVariable</span> <span class="comment">//获取路径中的参数信息(restful风格)</span></span><br><span class="line"><span class="meta">@RequestHeader</span> <span class="comment">//获取请求头的信息</span></span><br><span class="line"><span class="meta">@RequestAttribute</span> <span class="comment">//获取请求域中的数据</span></span><br><span class="line"><span class="meta">@RequestParam</span> <span class="comment">//获取路径中拼接的请求参数(/info?age=12&amp;name=lisi</span></span><br><span class="line"><span class="meta">@MatrixVariable</span> <span class="comment">//矩阵变量 /cars/sell;low=34;brand=byd,audi,yd </span></span><br><span class="line"><span class="meta">@CookieValue</span> <span class="comment">//获取cookie的值</span></span><br><span class="line"><span class="meta">@RequestBody</span> <span class="comment">//获取请求体的值(Post请求)</span></span><br></pre></td></tr></table></figure>
<p><strong>@PathVariable</strong></p>
<p>接受路径中的参数也可以使用map集合接受但是map集合必须是Map&lt;String, String&gt;的形式</p>
<p><img src="/pictures/image-20230809155753715.png" alt="image-20230809155753715"></p>
<p><strong>@RequestHeader</strong></p>
<p>获取指定的请求头或者所有的请求头信息</p>
<p><img src="/pictures/image-20230809160406516.png" alt="image-20230809160406516"></p>
<p><img src="/pictures/image-20230809160846527.png" alt="image-20230809160846527"></p>
<p><strong>@RequestParam</strong></p>
<p>可以使用map接受所有的请求参数</p>
<p><img src="/pictures/image-20230809161533834.png" alt="image-20230809161533834"></p>
<p><strong>@CookieValue</strong></p>
<p>获取cookie的值可以直接获取字符串的值也可以封装成cookie的对象</p>
<p><img src="/pictures/image-20230809164101374.png" alt="image-20230809164101374"></p>
<p><strong>@RequestBody</strong></p>
<p>这里用一个字符串接收表单数据和平时使用的不一样,开发中使用一个对象接受表单的数据</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ·<span class="doctag">@RequestBody</span>注解</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/save&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Map <span class="title function_">postMethod</span><span class="params">(<span class="meta">@RequestBody</span> String content)</span>&#123;</span><br><span class="line"> Map&lt;String,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"> map.put(<span class="string">&quot;content&quot;</span>,content);</span><br><span class="line"> <span class="keyword">return</span> map;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230809165149278.png" alt="image-20230809165149278"></p>
<p><strong>@RequestAttribute</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestAttribute;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/11</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RequestController</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(&quot;/goto&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">goToPage</span><span class="params">(HttpServletRequest request)</span>&#123;</span><br><span class="line"></span><br><span class="line"> request.setAttribute(<span class="string">&quot;msg&quot;</span>,<span class="string">&quot;获取请求域中的数据成功&quot;</span>);</span><br><span class="line"> request.setAttribute(<span class="string">&quot;code&quot;</span>,<span class="number">200</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;forward:/success&quot;</span>; <span class="comment">//转发到下面的/success请求</span></span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@ResponseBody</span></span><br><span class="line"> <span class="meta">@GetMapping(&quot;/success&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> Map <span class="title function_">success</span><span class="params">(<span class="meta">@RequestAttribute(value = &quot;msg&quot;,required = false)</span> String msg,</span></span><br><span class="line"><span class="params"> <span class="meta">@RequestAttribute(value = &quot;code&quot;,required = false)</span>Integer code,//通过注解的方式获取上面请求域的值</span></span><br><span class="line"><span class="params"> HttpServletRequest request)</span>&#123;<span class="comment">//通过原生的request获取</span></span><br><span class="line"> <span class="comment">//Object msg1 = request.getAttribute(&quot;msg&quot;);</span></span><br><span class="line"> Map&lt;String,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"> map.put(<span class="string">&quot;msg&quot;</span>,msg);</span><br><span class="line"> map.put(<span class="string">&quot;code&quot;</span>,code);</span><br><span class="line"> <span class="keyword">return</span> map;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230811092618793.png" alt="image-20230811092618793"></p>
<p><strong>@MatrixVariable</strong></p>
<p>开启SpringBoot的矩阵变量功能</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> WebMvcConfigurer <span class="title function_">webMvcConfigurer</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">WebMvcConfigurer</span>() &#123;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configurePathMatch</span><span class="params">(PathMatchConfigurer configurer)</span> &#123;</span><br><span class="line"> <span class="type">UrlPathHelper</span> <span class="variable">urlPathHelper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UrlPathHelper</span>();</span><br><span class="line"> <span class="comment">// 不移除 后面的内容 矩阵变量功能就可以生效</span></span><br><span class="line"> urlPathHelper.setRemoveSemicolonContent(<span class="literal">false</span>);</span><br><span class="line"> configurer.setUrlPathHelper(urlPathHelper);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、语法 请求路径:/cars/sell;low=34;brand=byd,audi,yd</span></span><br><span class="line"><span class="comment">//2、SpringBoot默认是禁用了矩阵变量的功能</span></span><br><span class="line"><span class="comment">// 手动开启原理。对于路径的处理。UrlPathHelper进行解析。</span></span><br><span class="line"><span class="comment">// removeSemicolonContent移除分号内容支持矩阵变量的</span></span><br><span class="line"><span class="comment">//3、矩阵变量必须有url路径变量才能被解析</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/cars/&#123;path&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Map <span class="title function_">carsSell</span><span class="params">(<span class="meta">@MatrixVariable(&quot;low&quot;)</span> Integer low,</span></span><br><span class="line"><span class="params"> <span class="meta">@MatrixVariable(&quot;brand&quot;)</span> List&lt;String&gt; brand,</span></span><br><span class="line"><span class="params"> <span class="meta">@PathVariable(&quot;path&quot;)</span> String path)</span>&#123;</span><br><span class="line"> Map&lt;String,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line"> map.put(<span class="string">&quot;low&quot;</span>,low);</span><br><span class="line"> map.put(<span class="string">&quot;brand&quot;</span>,brand);</span><br><span class="line"> map.put(<span class="string">&quot;path&quot;</span>,path);</span><br><span class="line"> <span class="keyword">return</span> map;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// /boss/1;age=20/2;age=10</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/boss/&#123;bossId&#125;/&#123;empId&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Map <span class="title function_">boss</span><span class="params">(<span class="meta">@MatrixVariable(value = &quot;age&quot;,pathVar = &quot;bossId&quot;)</span> Integer bossAge,</span></span><br><span class="line"><span class="params"> <span class="meta">@MatrixVariable(value = &quot;age&quot;,pathVar = &quot;empId&quot;)</span> Integer empAge)</span>&#123;</span><br><span class="line"> Map&lt;String,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"> map.put(<span class="string">&quot;bossAge&quot;</span>,bossAge);</span><br><span class="line"> map.put(<span class="string">&quot;empAge&quot;</span>,empAge);</span><br><span class="line"> <span class="keyword">return</span> map;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230811095858532.png" alt="image-20230811095858532"></p>
<p><img src="/pictures/image-20230811095834803.png" alt="image-20230811095834803"></p>
<h5 id="2-Servlet-API"><a href="#2-Servlet-API" class="headerlink" title="2.Servlet API"></a>2.Servlet API</h5><p>WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId</p>
<p>ServletRequestMethodArgumentResolver 以上的部分参数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsParameter</span><span class="params">(MethodParameter parameter)</span> &#123;</span><br><span class="line"> Class&lt;?&gt; paramType = parameter.getParameterType();</span><br><span class="line"> <span class="keyword">return</span> (WebRequest.class.isAssignableFrom(paramType) ||</span><br><span class="line"> ServletRequest.class.isAssignableFrom(paramType) ||</span><br><span class="line"> MultipartRequest.class.isAssignableFrom(paramType) ||</span><br><span class="line"> HttpSession.class.isAssignableFrom(paramType) ||</span><br><span class="line"> (pushBuilder != <span class="literal">null</span> &amp;&amp; pushBuilder.isAssignableFrom(paramType)) ||</span><br><span class="line"> Principal.class.isAssignableFrom(paramType) ||</span><br><span class="line"> InputStream.class.isAssignableFrom(paramType) ||</span><br><span class="line"> Reader.class.isAssignableFrom(paramType) ||</span><br><span class="line"> HttpMethod.class == paramType ||</span><br><span class="line"> Locale.class == paramType ||</span><br><span class="line"> TimeZone.class == paramType ||</span><br><span class="line"> ZoneId.class == paramType);</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>
<h5 id="3-复杂参数:"><a href="#3-复杂参数:" class="headerlink" title="3.复杂参数:"></a>3.复杂参数:</h5><p>Map、Modelmap、model里面的数据会被放在request的请求域 request.setAttribute、Errors&#x2F;BindingResult、RedirectAttributes 重定向携带数据、ServletResponseresponse、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder</p>
<p>向请求域中共享数据</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ra数据通过 map model HttpServletRequest HttpServletResponse 等方式共享到请求域中在success页面中取出来</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/params&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testParam</span><span class="params">(Map&lt;String,Object&gt; map,</span></span><br><span class="line"><span class="params"> Model model,</span></span><br><span class="line"><span class="params"> HttpServletRequest request,</span></span><br><span class="line"><span class="params"> HttpServletResponse response)</span>&#123;</span><br><span class="line"> map.put(<span class="string">&quot;hello&quot;</span>,<span class="string">&quot;world666&quot;</span>);</span><br><span class="line"> model.addAttribute(<span class="string">&quot;world&quot;</span>,<span class="string">&quot;hello666&quot;</span>);</span><br><span class="line"> request.setAttribute(<span class="string">&quot;message&quot;</span>,<span class="string">&quot;HelloWorld&quot;</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Cookie</span> <span class="variable">cookie</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Cookie</span>(<span class="string">&quot;c1&quot;</span>,<span class="string">&quot;v1&quot;</span>);</span><br><span class="line"> response.addCookie(cookie);</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;forward:/success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="4-自定义对象参数"><a href="#4-自定义对象参数" class="headerlink" title="4.自定义对象参数"></a>4.自定义对象参数</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 姓名: &lt;input name=&quot;userName&quot;/&gt; &lt;br/&gt;</span></span><br><span class="line"><span class="comment"> * 年龄: &lt;input name=&quot;age&quot;/&gt; &lt;br/&gt;</span></span><br><span class="line"><span class="comment"> * 生日: &lt;input name=&quot;birth&quot;/&gt; &lt;br/&gt;</span></span><br><span class="line"><span class="comment"> * 宠物姓名:&lt;input name=&quot;pet.name&quot;/&gt;&lt;br/&gt;</span></span><br><span class="line"><span class="comment"> * 宠物年龄:&lt;input name=&quot;pet.age&quot;/&gt;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> String userName;</span><br><span class="line"> <span class="keyword">private</span> Integer age;</span><br><span class="line"> <span class="keyword">private</span> Date birth;</span><br><span class="line"> <span class="keyword">private</span> Pet pet;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pet</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> String age;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>页面测试代码</strong></p>
<p>index.html</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html lang=<span class="string">&quot;en&quot;</span>&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line"> &lt;meta charset=<span class="string">&quot;UTF-8&quot;</span>&gt;</span><br><span class="line"> &lt;title&gt;Title&lt;/title&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;h1&gt;atguigu欢迎您&lt;/h1&gt;</span><br><span class="line">测试REST风格</span><br><span class="line">&lt;form action=<span class="string">&quot;/user&quot;</span> method=<span class="string">&quot;get&quot;</span>&gt;</span><br><span class="line"> &lt;input value=<span class="string">&quot;REST-GET 提交&quot;</span> type=<span class="string">&quot;submit&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;form action=<span class="string">&quot;/user&quot;</span> method=<span class="string">&quot;post&quot;</span>&gt;</span><br><span class="line"> &lt;input value=<span class="string">&quot;REST-POST 提交&quot;</span> type=<span class="string">&quot;submit&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;form action=<span class="string">&quot;/user&quot;</span> method=<span class="string">&quot;post&quot;</span>&gt;</span><br><span class="line"> &lt;input name=<span class="string">&quot;_method&quot;</span> type=<span class="string">&quot;hidden&quot;</span> value=<span class="string">&quot;delete&quot;</span>/&gt;</span><br><span class="line"> &lt;input name=<span class="string">&quot;_m&quot;</span> type=<span class="string">&quot;hidden&quot;</span> value=<span class="string">&quot;delete&quot;</span>/&gt;</span><br><span class="line"> &lt;input value=<span class="string">&quot;REST-DELETE 提交&quot;</span> type=<span class="string">&quot;submit&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;form action=<span class="string">&quot;/user&quot;</span> method=<span class="string">&quot;post&quot;</span>&gt;</span><br><span class="line"> &lt;input name=<span class="string">&quot;_method&quot;</span> type=<span class="string">&quot;hidden&quot;</span> value=<span class="string">&quot;PUT&quot;</span>/&gt;</span><br><span class="line"> &lt;input value=<span class="string">&quot;REST-PUT 提交&quot;</span> type=<span class="string">&quot;submit&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;hr/&gt;</span><br><span class="line">测试基本注解:</span><br><span class="line">&lt;ul&gt;</span><br><span class="line"> &lt;a href=<span class="string">&quot;car/3/owner/lisi?age=18&amp;inters=basketball&amp;inters=game&quot;</span>&gt;car/&#123;id&#125;/owner/&#123;username&#125;&lt;/a&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@PathVariable</span>(路径变量)&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@RequestHeader</span>(获取请求头)&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@RequestParam</span>(获取请求参数)&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@CookieValue</span>获取cookie值&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@RequestBody</span>(获取请求体[POST]&lt;/li&gt;</span><br><span class="line"></span><br><span class="line"> &lt;li&gt;<span class="meta">@RequestAttribute</span>获取request域属性&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;<span class="meta">@MatrixVariable</span>(矩阵变量)&lt;/li&gt;</span><br><span class="line">&lt;/ul&gt;</span><br><span class="line"></span><br><span class="line">/cars/&#123;path&#125;?xxx=xxx&amp;aaa=ccc queryString 查询字符串。<span class="meta">@RequestParam</span>&lt;br/&gt;</span><br><span class="line">/cars/sell;low=<span class="number">34</span>;brand=byd,audi,yd ;矩阵变量 &lt;br/&gt;</span><br><span class="line">页面开发cookie禁用了session里面的内容怎么使用</span><br><span class="line">session.set(a,b)---&gt; jsessionid ---&gt; cookie ----&gt; 每次发请求携带。</span><br><span class="line">url重写/abc;jsesssionid=xxxx 把cookie的值使用矩阵变量的方式进行传递.</span><br><span class="line"></span><br><span class="line">/boss/<span class="number">1</span>/<span class="number">2</span></span><br><span class="line"></span><br><span class="line">/boss/<span class="number">1</span>;age=<span class="number">20</span>/<span class="number">2</span>;age=<span class="number">20</span></span><br><span class="line"></span><br><span class="line">&lt;a href=<span class="string">&quot;/cars/sell;low=34;brand=byd,audi,yd&quot;</span>&gt;<span class="meta">@MatrixVariable</span>(矩阵变量)&lt;/a&gt;</span><br><span class="line">&lt;a href=<span class="string">&quot;/cars/sell;low=34;brand=byd;brand=audi;brand=yd&quot;</span>&gt;<span class="meta">@MatrixVariable</span>(矩阵变量)&lt;/a&gt;</span><br><span class="line">&lt;a href=<span class="string">&quot;/boss/1;age=20/2;age=10&quot;</span>&gt;<span class="meta">@MatrixVariable</span>(矩阵变量)/boss/&#123;bossId&#125;/&#123;empId&#125;&lt;/a&gt;</span><br><span class="line">&lt;br/&gt;</span><br><span class="line">&lt;form action=<span class="string">&quot;/save&quot;</span> method=<span class="string">&quot;post&quot;</span>&gt;</span><br><span class="line"> 测试<span class="meta">@RequestBody</span>获取数据 &lt;br/&gt;</span><br><span class="line"> 用户名:&lt;input name=<span class="string">&quot;userName&quot;</span>/&gt; &lt;br&gt;</span><br><span class="line"> 邮箱:&lt;input name=<span class="string">&quot;email&quot;</span>/&gt;</span><br><span class="line"> &lt;input type=<span class="string">&quot;submit&quot;</span> value=<span class="string">&quot;提交&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;ol&gt;</span><br><span class="line"> &lt;li&gt;矩阵变量需要在SpringBoot中手动开启&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;根据RFC3986的规范矩阵变量应当绑定在路径变量中&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;若是有多个矩阵变量,应当使用英文符号;进行分隔。&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;若是一个矩阵变量有多个值,应当使用英文符号,进行分隔或之命名多个重复的key即可。&lt;/li&gt;</span><br><span class="line"> &lt;li&gt;如:/cars/sell;low=<span class="number">34</span>;brand=byd,audi,yd&lt;/li&gt;</span><br><span class="line">&lt;/ol&gt;</span><br><span class="line">&lt;hr/&gt;</span><br><span class="line">测试原生API</span><br><span class="line">&lt;a href=<span class="string">&quot;/testapi&quot;</span>&gt;测试原生API&lt;/a&gt;</span><br><span class="line">&lt;hr/&gt;</span><br><span class="line">测试复杂类型:&lt;hr/&gt;</span><br><span class="line">测试封装POJO</span><br><span class="line">&lt;form action=<span class="string">&quot;/saveuser&quot;</span> method=<span class="string">&quot;post&quot;</span>&gt;</span><br><span class="line"> 姓名: &lt;input name=<span class="string">&quot;userName&quot;</span> value=<span class="string">&quot;zhangsan&quot;</span>/&gt; &lt;br/&gt;</span><br><span class="line"> 年龄: &lt;input name=<span class="string">&quot;age&quot;</span> value=<span class="string">&quot;18&quot;</span>/&gt; &lt;br/&gt;</span><br><span class="line"> 生日: &lt;input name=<span class="string">&quot;birth&quot;</span> value=<span class="string">&quot;2019/12/10&quot;</span>/&gt; &lt;br/&gt;</span><br><span class="line">&lt;!-- 宠物姓名:&lt;input name=<span class="string">&quot;pet.name&quot;</span> value=<span class="string">&quot;阿猫&quot;</span>/&gt;&lt;br/&gt;--&gt;</span><br><span class="line">&lt;!-- 宠物年龄:&lt;input name=<span class="string">&quot;pet.age&quot;</span> value=<span class="string">&quot;5&quot;</span>/&gt;--&gt;</span><br><span class="line"> 宠物: &lt;input name=<span class="string">&quot;pet&quot;</span> value=<span class="string">&quot;小猫&quot;</span>/&gt;</span><br><span class="line"> &lt;input type=<span class="string">&quot;submit&quot;</span> value=<span class="string">&quot;保存&quot;</span>/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;br&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure>
<h4 id="2-3-参数处理原理"><a href="#2-3-参数处理原理" class="headerlink" title="2.3 参数处理原理"></a>2.3 参数处理原理</h4><p><strong>1.页面发送请求</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:8080/car/3/owner/lisi </span><br></pre></td></tr></table></figure>
<p><strong>2.进入DispatcherServlet的doDispatch( )方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doDispatch</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">processedRequest</span> <span class="operator">=</span> request;</span><br><span class="line"> <span class="type">HandlerExecutionChain</span> <span class="variable">mappedHandler</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">multipartRequestParsed</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">WebAsyncManager</span> <span class="variable">asyncManager</span> <span class="operator">=</span> WebAsyncUtils.getAsyncManager(request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="type">ModelAndView</span> <span class="variable">mv</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="type">Exception</span> <span class="variable">dispatchException</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> processedRequest = checkMultipart(request);</span><br><span class="line"> multipartRequestParsed = (processedRequest != request);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Determine handler for the current request.</span></span><br><span class="line"> mappedHandler = getHandler(processedRequest);</span><br><span class="line"> <span class="keyword">if</span> (mappedHandler == <span class="literal">null</span>) &#123;</span><br><span class="line"> noHandlerFound(processedRequest, response);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Determine handler adapter for the current request.</span></span><br><span class="line"> <span class="type">HandlerAdapter</span> <span class="variable">ha</span> <span class="operator">=</span> getHandlerAdapter(mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Process last-modified header, if supported by the handler.</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> request.getMethod();</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isGet</span> <span class="operator">=</span> <span class="string">&quot;GET&quot;</span>.equals(method);</span><br><span class="line"> <span class="keyword">if</span> (isGet || <span class="string">&quot;HEAD&quot;</span>.equals(method)) &#123;</span><br><span class="line"> <span class="type">long</span> <span class="variable">lastModified</span> <span class="operator">=</span> ha.getLastModified(request, mappedHandler.getHandler());</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">new</span> <span class="title class_">ServletWebRequest</span>(request, response).checkNotModified(lastModified) &amp;&amp; isGet) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!mappedHandler.applyPreHandle(processedRequest, response)) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Actually invoke the handler.</span></span><br><span class="line"> mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> applyDefaultViewName(processedRequest, mv);</span><br><span class="line"> mappedHandler.applyPostHandle(processedRequest, response, mv);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> dispatchException = ex;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line"> <span class="comment">// As of 4.3, we&#x27;re processing Errors thrown from handler methods as well,</span></span><br><span class="line"> <span class="comment">// making them available for @ExceptionHandler methods and other scenarios.</span></span><br><span class="line"> dispatchException = <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler dispatch failed&quot;</span>, err);</span><br><span class="line"> &#125;</span><br><span class="line"> processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> triggerAfterCompletion(processedRequest, response, mappedHandler, ex);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Throwable err) &#123;</span><br><span class="line"> triggerAfterCompletion(processedRequest, response, mappedHandler,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">NestedServletException</span>(<span class="string">&quot;Handler processing failed&quot;</span>, err));</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">finally</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line"> <span class="comment">// Instead of postHandle and afterCompletion</span></span><br><span class="line"> <span class="keyword">if</span> (mappedHandler != <span class="literal">null</span>) &#123;</span><br><span class="line"> mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="comment">// Clean up any resources used by a multipart request.</span></span><br><span class="line"> <span class="keyword">if</span> (multipartRequestParsed) &#123;</span><br><span class="line"> cleanupMultipart(processedRequest);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>3.封装一个方法获取对应的处理器适配器</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//方法的调用</span></span><br><span class="line"><span class="type">HandlerAdapter</span> <span class="variable">ha</span> <span class="operator">=</span> getHandlerAdapter(mappedHandler.getHandler());</span><br></pre></td></tr></table></figure>
<p><strong>4.遍历所有的处理器适配器(一共有四种,如下图)找到支持的适配器</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> HandlerAdapter <span class="title function_">getHandlerAdapter</span><span class="params">(Object handler)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.handlerAdapters != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">for</span> (HandlerAdapter adapter : <span class="built_in">this</span>.handlerAdapters) &#123;</span><br><span class="line"> <span class="keyword">if</span> (adapter.supports(handler)) &#123;</span><br><span class="line"> <span class="keyword">return</span> adapter;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ServletException</span>(<span class="string">&quot;No adapter for handler [&quot;</span> + handler +</span><br><span class="line"> <span class="string">&quot;]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230812091950114.png" alt="image-20230812091950114"></p>
<p>上图中四个处理器适配器中前两个是常用的处理器适配器: 0 - 支持方法上标注@RequestMapping 1 - 支持函数式编程的</p>
<p><strong>5.查看当前的处理器适配器是否支持的方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">supports</span><span class="params">(Object handler)</span> &#123;</span><br><span class="line"> <span class="comment">//条件一 handler instanceof HandlerMethod</span></span><br><span class="line"> <span class="comment">//条件二 supportsInternal((HandlerMethod) handler)</span></span><br><span class="line"> <span class="keyword">return</span> (handler <span class="keyword">instanceof</span> HandlerMethod &amp;&amp; supportsInternal((HandlerMethod) handler));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>遍历查找之后返回的适配器是RequestMappingHandlerAdapter</p>
<p><img src="/pictures/image-20230812092825385.png" alt="image-20230812092825385"></p>
<p><strong>6.回到DispatcherServlet执行下面的方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//根据上面获取到的处理器适配器真正的执行处理器方法</span></span><br><span class="line"><span class="comment">// Actually invoke the handler.</span></span><br><span class="line">mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span><br></pre></td></tr></table></figure>
<p><strong>7.内部的处理过程</strong></p>
<p>handle( )方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> ModelAndView <span class="title function_">handle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span></span><br><span class="line"><span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="keyword">return</span> handleInternal(request, response, (HandlerMethod) handler);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>进入当前处理器适配器的handleInternal( )方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> ModelAndView <span class="title function_">handleInternal</span><span class="params">(HttpServletRequest request,</span></span><br><span class="line"><span class="params"> HttpServletResponse response, HandlerMethod handlerMethod)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> ModelAndView mav;</span><br><span class="line"> checkRequest(request);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Execute invokeHandlerMethod in synchronized block if required.</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.synchronizeOnSession) &#123;</span><br><span class="line"> <span class="type">HttpSession</span> <span class="variable">session</span> <span class="operator">=</span> request.getSession(<span class="literal">false</span>);</span><br><span class="line"> <span class="keyword">if</span> (session != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="type">Object</span> <span class="variable">mutex</span> <span class="operator">=</span> WebUtils.getSessionMutex(session);</span><br><span class="line"> <span class="keyword">synchronized</span> (mutex) &#123;</span><br><span class="line"> mav = invokeHandlerMethod(request, response, handlerMethod);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="comment">// No HttpSession available -&gt; no mutex necessary</span></span><br><span class="line"> mav = invokeHandlerMethod(request, response, handlerMethod);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="comment">// No synchronization on session demanded at all...</span></span><br><span class="line"> mav = invokeHandlerMethod(request, response, handlerMethod);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!response.containsHeader(HEADER_CACHE_CONTROL)) &#123;</span><br><span class="line"> <span class="keyword">if</span> (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) &#123;</span><br><span class="line"> applyCacheSeconds(response, <span class="built_in">this</span>.cacheSecondsForSessionAttributeHandlers);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> &#123;</span><br><span class="line"> prepareResponse(response);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> mav;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>执行invokeHandlerMethod( )方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mav = invokeHandlerMethod(request, response, handlerMethod);</span><br></pre></td></tr></table></figure>
<p>进入invokeHandlerMethod()方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">protected</span> ModelAndView <span class="title function_">invokeHandlerMethod</span><span class="params">(HttpServletRequest request,</span></span><br><span class="line"><span class="params"> HttpServletResponse response, HandlerMethod handlerMethod)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">ServletWebRequest</span> <span class="variable">webRequest</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ServletWebRequest</span>(request, response);</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="type">WebDataBinderFactory</span> <span class="variable">binderFactory</span> <span class="operator">=</span> getDataBinderFactory(handlerMethod);</span><br><span class="line"> <span class="type">ModelFactory</span> <span class="variable">modelFactory</span> <span class="operator">=</span> getModelFactory(handlerMethod, binderFactory);</span><br><span class="line"></span><br><span class="line"> <span class="type">ServletInvocableHandlerMethod</span> <span class="variable">invocableMethod</span> <span class="operator">=</span> createInvocableHandlerMethod(handlerMethod);</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.argumentResolvers != <span class="literal">null</span>) &#123;</span><br><span class="line"> invocableMethod.setHandlerMethodArgumentResolvers(<span class="built_in">this</span>.argumentResolvers);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.returnValueHandlers != <span class="literal">null</span>) &#123;</span><br><span class="line"> invocableMethod.setHandlerMethodReturnValueHandlers(<span class="built_in">this</span>.returnValueHandlers);</span><br><span class="line"> &#125;</span><br><span class="line"> invocableMethod.setDataBinderFactory(binderFactory);</span><br><span class="line"> invocableMethod.setParameterNameDiscoverer(<span class="built_in">this</span>.parameterNameDiscoverer);</span><br><span class="line"></span><br><span class="line"> <span class="type">ModelAndViewContainer</span> <span class="variable">mavContainer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ModelAndViewContainer</span>();</span><br><span class="line"> mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));</span><br><span class="line"> modelFactory.initModel(webRequest, mavContainer, invocableMethod);</span><br><span class="line"> mavContainer.setIgnoreDefaultModelOnRedirect(<span class="built_in">this</span>.ignoreDefaultModelOnRedirect);</span><br><span class="line"></span><br><span class="line"> <span class="type">AsyncWebRequest</span> <span class="variable">asyncWebRequest</span> <span class="operator">=</span> WebAsyncUtils.createAsyncWebRequest(request, response);</span><br><span class="line"> asyncWebRequest.setTimeout(<span class="built_in">this</span>.asyncRequestTimeout);</span><br><span class="line"></span><br><span class="line"> <span class="type">WebAsyncManager</span> <span class="variable">asyncManager</span> <span class="operator">=</span> WebAsyncUtils.getAsyncManager(request);</span><br><span class="line"> asyncManager.setTaskExecutor(<span class="built_in">this</span>.taskExecutor);</span><br><span class="line"> asyncManager.setAsyncWebRequest(asyncWebRequest);</span><br><span class="line"> asyncManager.registerCallableInterceptors(<span class="built_in">this</span>.callableInterceptors);</span><br><span class="line"> asyncManager.registerDeferredResultInterceptors(<span class="built_in">this</span>.deferredResultInterceptors);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (asyncManager.hasConcurrentResult()) &#123;</span><br><span class="line"> <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> asyncManager.getConcurrentResult();</span><br><span class="line"> mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[<span class="number">0</span>];</span><br><span class="line"> asyncManager.clearConcurrentResult();</span><br><span class="line"> LogFormatUtils.traceDebug(logger, traceOn -&gt; &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">formatted</span> <span class="operator">=</span> LogFormatUtils.formatValue(result, !traceOn);</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;Resume with async result [&quot;</span> + formatted + <span class="string">&quot;]&quot;</span>;</span><br><span class="line"> &#125;);</span><br><span class="line"> invocableMethod = invocableMethod.wrapConcurrentResult(result);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> invocableMethod.invokeAndHandle(webRequest, mavContainer);</span><br><span class="line"> <span class="keyword">if</span> (asyncManager.isConcurrentHandlingStarted()) &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> getModelAndView(mavContainer, modelFactory, webRequest);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">finally</span> &#123;</span><br><span class="line"> webRequest.requestCompleted();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>注意这里的26个参数解析器参数解析器的作用是确定将要执行的目标方法的每一个参数的值是什么</p>
<p>这里的每一个参数解析器都对应了我们标注在参数上的注解</p>
<p>SpringMVC目标方法能写多少种参数类型取决于参数解析器</p>
<p><img src="/pictures/image-20230812094224699.png" alt="image-20230812094224699"></p>
<p>参数解析器的接口设计</p>
<p><img src="/pictures/image-20230812094755583.png" alt="image-20230812094755583"></p>
<ul>
<li>当前解析器是否支持解析这种参数</li>
<li>支持就调用 resolveArgument</li>
</ul>
<p>返回值处理器</p>
<p>定义了controller返回值的类型</p>
<img src="/pictures/image-20230812095137195.png" alt="image-20230812095137195" style="zoom:150%;" />
<p>RequestMappingHandlerAdapter的invokeAndHandle( )方法真正的执行请求</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">invocableMethod.invokeAndHandle(webRequest, mavContainer);</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">invokeAndHandle</span><span class="params">(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,</span></span><br><span class="line"><span class="params"> Object... providedArgs)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">Object</span> <span class="variable">returnValue</span> <span class="operator">=</span> invokeForRequest(webRequest, mavContainer, providedArgs);</span><br><span class="line"> <span class="comment">//上面一行代码执行完毕之后会直接跳到controller方法然后执行下面的代码</span></span><br><span class="line"> setResponseStatus(webRequest);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (returnValue == <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">if</span> (isRequestNotModified(webRequest) || getResponseStatus() != <span class="literal">null</span> || mavContainer.isRequestHandled()) &#123;</span><br><span class="line"> disableContentCachingIfNecessary(webRequest);</span><br><span class="line"> mavContainer.setRequestHandled(<span class="literal">true</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (StringUtils.hasText(getResponseStatusReason())) &#123;</span><br><span class="line"> mavContainer.setRequestHandled(<span class="literal">true</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> mavContainer.setRequestHandled(<span class="literal">false</span>);</span><br><span class="line"> Assert.state(<span class="built_in">this</span>.returnValueHandlers != <span class="literal">null</span>, <span class="string">&quot;No return value handlers&quot;</span>);</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="built_in">this</span>.returnValueHandlers.handleReturnValue(</span><br><span class="line"> returnValue, getReturnValueType(returnValue), mavContainer, webRequest);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line"> logger.trace(formatErrorForReturnValue(returnValue), ex);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">throw</span> ex;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>执行的过程</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Object</span> <span class="variable">returnValue</span> <span class="operator">=</span> invokeForRequest(webRequest, mavContainer, providedArgs);</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">invokeForRequest</span><span class="params">(NativeWebRequest request, <span class="meta">@Nullable</span> ModelAndViewContainer mavContainer,</span></span><br><span class="line"><span class="params"> Object... providedArgs)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);</span><br><span class="line"> <span class="comment">//这个args就记录了方法上所有的参数</span></span><br><span class="line"> <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line"> logger.trace(<span class="string">&quot;Arguments: &quot;</span> + Arrays.toString(args));</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> doInvoke(args);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230812100059378.png" alt="image-20230812100059378"></p>
<p>获取方法参数值的过程</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> Object[] getMethodArgumentValues(NativeWebRequest request, <span class="meta">@Nullable</span> ModelAndViewContainer mavContainer,</span><br><span class="line"> Object... providedArgs) <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获取所有参数的参数声明 参数类型 标注的注解 </span></span><br><span class="line"> MethodParameter[] parameters = getMethodParameters();</span><br><span class="line"> <span class="keyword">if</span> (ObjectUtils.isEmpty(parameters)) &#123;</span><br><span class="line"> <span class="keyword">return</span> EMPTY_ARGS;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> Object[] args = <span class="keyword">new</span> <span class="title class_">Object</span>[parameters.length];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; parameters.length; i++) &#123;</span><br><span class="line"> <span class="type">MethodParameter</span> <span class="variable">parameter</span> <span class="operator">=</span> parameters[i];</span><br><span class="line"> parameter.initParameterNameDiscovery(<span class="built_in">this</span>.parameterNameDiscoverer);</span><br><span class="line"> args[i] = findProvidedArgument(parameter, providedArgs);</span><br><span class="line"> <span class="keyword">if</span> (args[i] != <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">this</span>.resolvers.supportsParameter(parameter)) &#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(formatArgumentError(parameter, <span class="string">&quot;No suitable resolver&quot;</span>));</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> args[i] = <span class="built_in">this</span>.resolvers.resolveArgument(parameter, mavContainer, request, <span class="built_in">this</span>.dataBinderFactory);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line"> <span class="comment">// Leave stack trace for later, exception may actually be resolved and handled...</span></span><br><span class="line"> <span class="keyword">if</span> (logger.isDebugEnabled()) &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">exMsg</span> <span class="operator">=</span> ex.getMessage();</span><br><span class="line"> <span class="keyword">if</span> (exMsg != <span class="literal">null</span> &amp;&amp; !exMsg.contains(parameter.getExecutable().toGenericString())) &#123;</span><br><span class="line"> logger.debug(formatArgumentError(parameter, exMsg));</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">throw</span> ex;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> args;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>遍历判断获取支持解析该参数的参数解析器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">private</span> HandlerMethodArgumentResolver <span class="title function_">getArgumentResolver</span><span class="params">(MethodParameter parameter)</span> &#123;</span><br><span class="line"> <span class="type">HandlerMethodArgumentResolver</span> <span class="variable">result</span> <span class="operator">=</span> <span class="built_in">this</span>.argumentResolverCache.get(parameter);</span><br><span class="line"> <span class="keyword">if</span> (result == <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">for</span> (HandlerMethodArgumentResolver resolver : <span class="built_in">this</span>.argumentResolvers) &#123;</span><br><span class="line"> <span class="keyword">if</span> (resolver.supportsParameter(parameter)) &#123;</span><br><span class="line"> result = resolver;</span><br><span class="line"> <span class="built_in">this</span>.argumentResolverCache.put(parameter, result);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>解析参数的值通过调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法</p>
<h4 id="2-4-数据响应与内容协商"><a href="#2-4-数据响应与内容协商" class="headerlink" title="2.4 数据响应与内容协商"></a>2.4 数据响应与内容协商</h4><p>返回值的处理逻辑</p>
<h5 id="2-4-1-相关依赖的引入"><a href="#2-4-1-相关依赖的引入" class="headerlink" title="2.4.1 相关依赖的引入"></a>2.4.1 相关依赖的引入</h5><p>创建springBoot项目的时候导入了spring-boot-starter-web依赖会自动的帮我们导入相关的json依赖便于json数据的前后端传递</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>自动的帮我们导入相关的json的starter</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-json<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.4.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在spring-boot-starter-json中引入了jackson相关的依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-databind<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.11.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.datatype<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-datatype-jdk8<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.11.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.datatype<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-datatype-jsr310<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.11.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.module<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-module-parameter-names<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.11.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><strong>返回值解析器的原理</strong></p>
<ul>
<li><p>1、返回值处理器判断是否支持这种类型返回值 supportsReturnType</p>
</li>
<li><p>2、返回值处理器调用 handleReturnValue 进行处理</p>
</li>
<li><p>3、RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。</p>
</li>
<li><ul>
<li><ol>
<li>利用 MessageConverters 进行处理 将数据写为json</li>
</ol>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>1、内容协商浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型</li>
<li>2、服务器最终根据自己自身的能力决定服务器能生产出什么样内容类型的数据</li>
<li>3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li><ul>
<li>1、得到MappingJackson2HttpMessageConverter可以将对象写为json</li>
<li>2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h5 id="2-4-2-内容协商原理"><a href="#2-4-2-内容协商原理" class="headerlink" title="2.4.2 内容协商原理"></a>2.4.2 内容协商原理</h5><p>引入jackson-dataformat-xml测试返回是xml格式的数据</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.dataformat<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-dataformat-xml<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>开启基于请求参数的内容协商功能</p>
<p>发请求: <a target="_blank" rel="noopener" href="http://localhost:8080/test/person?format=json">http://localhost:8080/test/person?format=json</a> &#x2F;&#x2F;指定格式是json </p>
<p> <a target="_blank" rel="noopener" href="http://localhost:8080/test/person?format=xml">http://localhost:8080/test/person?format=xml</a> &#x2F;&#x2F;指定格式是xml</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">contentnegotiation:</span></span><br><span class="line"> <span class="attr">favor-parameter:</span> <span class="literal">true</span> <span class="comment">#开启请求参数内容协商模式</span></span><br></pre></td></tr></table></figure>
<p>1、Parameter策略优先确定是要返回json数据获取请求头中的format的值</p>
<p>2、最终进行内容协商返回给客户端json即可</p>
<p>3、遍历循环所有当前系统的 MessageConverter看谁支持操作这个对象Person</p>
<p>4、找到支持操作Person的converter把converter支持的媒体类型统计出来。</p>
<p>5、客户端需要【application&#x2F;xml】。服务端能力【10种、json、xml】</p>
<p>6、进行内容协商的最佳匹配媒体类型</p>
<p>7、用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化 。</p>
<h5 id="2-4-3-自定义MessageConverter"><a href="#2-4-3-自定义MessageConverter" class="headerlink" title="2.4.3 自定义MessageConverter"></a>2.4.3 自定义MessageConverter</h5><p>1、@ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理</p>
<p>2、Processor 处理方法返回值。通过 MessageConverter 处理</p>
<p>3、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)</p>
<p>4、内容协商找到最终的 messageConverter</p>
<p> <strong>步骤:</strong><br>1、添加自定义的MessageConverter进系统底层</p>
<p>2、系统底层就会统计出所有MessageConverter能操作哪些类型</p>
<p>3、客户端内容协商 [guigu—&gt;guigu]</p>
<p>编写自定义的的converter</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.converter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.bean.Person;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpInputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpOutputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.MediaType;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotReadableException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotWritableException;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义的Converter</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GuiguMessageConverter</span> <span class="keyword">implements</span> <span class="title class_">HttpMessageConverter</span>&lt;Person&gt; &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">canRead</span><span class="params">(Class&lt;?&gt; clazz, MediaType mediaType)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">canWrite</span><span class="params">(Class&lt;?&gt; clazz, MediaType mediaType)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> clazz.isAssignableFrom(Person.class);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 服务器要统计所有MessageConverter都能写出哪些内容类型</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * application/x-guigu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> List&lt;MediaType&gt; <span class="title function_">getSupportedMediaTypes</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> MediaType.parseMediaTypes(<span class="string">&quot;application/x-guigu&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Person <span class="title function_">read</span><span class="params">(Class&lt;? extends Person&gt; clazz, HttpInputMessage inputMessage)</span> <span class="keyword">throws</span> IOException, HttpMessageNotReadableException &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">(Person person, MediaType contentType, HttpOutputMessage outputMessage)</span> <span class="keyword">throws</span> IOException, HttpMessageNotWritableException &#123;</span><br><span class="line"> <span class="comment">//自定义协议数据的写出</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">data</span> <span class="operator">=</span> person.getUserName()+<span class="string">&quot;;&quot;</span>+person.getAge()+<span class="string">&quot;;&quot;</span>+person.getBirth();</span><br><span class="line"> <span class="comment">//写出去</span></span><br><span class="line"> <span class="type">OutputStream</span> <span class="variable">body</span> <span class="operator">=</span> outputMessage.getBody();</span><br><span class="line"> body.write(data.getBytes());</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在配置文件中加入自定义的converter</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.config;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.bean.Person;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.bean.Pet;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.converter.GuiguMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.convert.converter.Converter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.format.FormatterRegistry;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpInputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpOutputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.MediaType;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotReadableException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotWritableException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.accept.HeaderContentNegotiationStrategy;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.accept.ParameterContentNegotiationStrategy;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.HiddenHttpMethodFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.PathMatchConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.util.UrlPathHelper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> &#123;</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> WebMvcConfigurer <span class="title function_">webMvcConfigurer</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">WebMvcConfigurer</span>() &#123;</span><br><span class="line"> <span class="comment">//加入自定义的converter</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">extendMessageConverters</span><span class="params">(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters)</span> &#123;</span><br><span class="line"> converters.add(<span class="keyword">new</span> <span class="title class_">GuiguMessageConverter</span>());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在浏览器url上拼接参数的形式实现内容协商</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.bean.Person;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.bean.Pet;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.boot.converter.GuiguMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.convert.converter.Converter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.format.FormatterRegistry;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpInputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpOutputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.MediaType;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotReadableException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.HttpMessageNotWritableException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.accept.HeaderContentNegotiationStrategy;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.accept.ParameterContentNegotiationStrategy;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.HiddenHttpMethodFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.PathMatchConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.util.UrlPathHelper;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> WebMvcConfigurer <span class="title function_">webMvcConfigurer</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">WebMvcConfigurer</span>() &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义内容协商策略</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> configurer</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureContentNegotiation</span><span class="params">(ContentNegotiationConfigurer configurer)</span> &#123;</span><br><span class="line"> Map&lt;String, MediaType&gt; mediaTypes = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"> mediaTypes.put(<span class="string">&quot;json&quot;</span>,MediaType.APPLICATION_JSON);</span><br><span class="line"> mediaTypes.put(<span class="string">&quot;xml&quot;</span>,MediaType.APPLICATION_XML);</span><br><span class="line"> <span class="comment">//在浏览器url上拼接参数的形式实现内容协商</span></span><br><span class="line"> <span class="comment">//http://localhost:8080/test/person?format=gg</span></span><br><span class="line"> mediaTypes.put(<span class="string">&quot;gg&quot;</span>,MediaType.parseMediaType(<span class="string">&quot;application/x-guigu&quot;</span>));</span><br><span class="line"> <span class="comment">//指定支持解析哪些参数对应的哪些媒体类型</span></span><br><span class="line"> <span class="type">ParameterContentNegotiationStrategy</span> <span class="variable">parameterStrategy</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ParameterContentNegotiationStrategy</span>(mediaTypes);</span><br><span class="line"> <span class="comment">//parameterStrategy.setParameterName(&quot;ff&quot;);</span></span><br><span class="line"></span><br><span class="line"> <span class="type">HeaderContentNegotiationStrategy</span> <span class="variable">headeStrategy</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HeaderContentNegotiationStrategy</span>();</span><br><span class="line"></span><br><span class="line"> configurer.strategies(Arrays.asList(parameterStrategy,headeStrategy));</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//加入自定义的converter</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">extendMessageConverters</span><span class="params">(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters)</span> &#123;</span><br><span class="line"> converters.add(<span class="keyword">new</span> <span class="title class_">GuiguMessageConverter</span>());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-视图解析与模板引擎"><a href="#3-视图解析与模板引擎" class="headerlink" title="3.视图解析与模板引擎"></a>3.视图解析与模板引擎</h3><p>视图解析SpringBoot默认不支持 JSP需要引入第三方模板引擎技术实现页面渲染</p>
<h4 id="3-1-视图解析"><a href="#3-1-视图解析" class="headerlink" title="3.1 视图解析"></a>3.1 视图解析</h4><p><img src="/pictures/image-20230815091741019.png" alt="image-20230815091741019"></p>
<h4 id="3-2-模板引擎-Thymeleaf"><a href="#3-2-模板引擎-Thymeleaf" class="headerlink" title="3.2 模板引擎-Thymeleaf"></a>3.2 模板引擎-Thymeleaf</h4><p>详细的使用教程: <a href="https://qingling.icu/posts/54835.html">https://qingling.icu/posts/54835.html</a></p>
<h5 id="3-2-1-Thymeleaf的使用"><a href="#3-2-1-Thymeleaf的使用" class="headerlink" title="3.2.1 Thymeleaf的使用"></a>3.2.1 Thymeleaf的使用</h5><p>1.引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2.编写测试controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ViewTestController</span> &#123;</span><br><span class="line"> <span class="meta">@GetMapping(&quot;/view&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">(Model model)</span>&#123;</span><br><span class="line"> <span class="comment">//向请求域中共享数据</span></span><br><span class="line"> model.addAttribute(<span class="string">&quot;keys&quot;</span>,<span class="string">&quot;Thymeleaf&quot;</span>);</span><br><span class="line"> <span class="comment">//转发到success页面中</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>3.页面上渲染</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">title</span>&gt;</span>Title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;keys&#125;&quot;</span>&gt;</span>Hello<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230815153318041.png" alt="image-20230815153318041"></p>
<h4 id="3-3-后台管理系统注意点"><a href="#3-3-后台管理系统注意点" class="headerlink" title="3.3 后台管理系统注意点"></a>3.3 后台管理系统注意点</h4><p><strong>templates目录的访问规则</strong></p>
<p>templates目录下的所有页面资源只能通过请求访问到</p>
<p><strong>表单重复提交的问题</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.admin.controller;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">IndexController</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 来登录页</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@GetMapping(value = &#123;&quot;/&quot;,&quot;/login&quot;&#125;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">loginPage</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;login&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping(&quot;/login&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">main</span><span class="params">(String username, String password)</span>&#123;</span><br><span class="line"> <span class="comment">//登录成功重定向到main.html; 重定向防止表单重复提交</span></span><br><span class="line"> <span class="comment">//这里如果直接写 return &quot;main&quot;的话页面在mian.html的情况下url路径还是localhost:8080/login,如果再次刷新页面会重复提交表单</span></span><br><span class="line"> <span class="comment">//使用下面这个写法,执行&quot;/login&quot;这个请求之后路径的url会变成localhost:8080/main.html</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;redirect:/main.html&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 去main页面</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@GetMapping(&quot;/main.html&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">mainPage</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;main&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-拦截器"><a href="#4-拦截器" class="headerlink" title="4.拦截器"></a>4.拦截器</h3><h4 id="1-HandlerInterceptor接口"><a href="#1-HandlerInterceptor接口" class="headerlink" title="1.HandlerInterceptor接口"></a>1.HandlerInterceptor接口</h4><p>自定义拦截器需要实现的接口,以及需要实现接口中的方法</p>
<p><img src="/pictures/image-20230821105529796.png" alt="image-20230821105529796"></p>
<h4 id="2-拦截器实现登录检查操作"><a href="#2-拦截器实现登录检查操作" class="headerlink" title="2.拦截器实现登录检查操作"></a>2.拦截器实现登录检查操作</h4><p><strong>登录检查的业务逻辑</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 登录检查</span></span><br><span class="line"><span class="comment"> * 1、配置好拦截器要拦截哪些请求</span></span><br><span class="line"><span class="comment"> * 2、把这些配置放在容器中</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoginInterceptor</span> <span class="keyword">implements</span> <span class="title class_">HandlerInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 目标方法执行之前</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">preHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">requestURI</span> <span class="operator">=</span> request.getRequestURI();</span><br><span class="line"> log.info(<span class="string">&quot;preHandle拦截的请求路径是&#123;&#125;&quot;</span>,requestURI);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//登录检查逻辑</span></span><br><span class="line"> <span class="type">HttpSession</span> <span class="variable">session</span> <span class="operator">=</span> request.getSession();</span><br><span class="line"></span><br><span class="line"> <span class="type">Object</span> <span class="variable">loginUser</span> <span class="operator">=</span> session.getAttribute(<span class="string">&quot;loginUser&quot;</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(loginUser != <span class="literal">null</span>)&#123;</span><br><span class="line"> <span class="comment">//放行</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//拦截住 未登录 跳转到登录页</span></span><br><span class="line"> request.setAttribute(<span class="string">&quot;msg&quot;</span>,<span class="string">&quot;请先登录&quot;</span>);</span><br><span class="line"> request.getRequestDispatcher(<span class="string">&quot;/&quot;</span>).forward(request,response);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 目标方法执行完成以后</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> modelAndView</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> log.info(<span class="string">&quot;postHandle执行&#123;&#125;&quot;</span>,modelAndView);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 页面渲染以后</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> ex</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterCompletion</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> log.info(<span class="string">&quot;afterCompletion执行异常&#123;&#125;&quot;</span>,ex);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>拦截器的配置</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1、编写一个拦截器实现HandlerInterceptor接口</span></span><br><span class="line"><span class="comment"> * 2、拦截器注册到容器中实现WebMvcConfigurer的addInterceptors</span></span><br><span class="line"><span class="comment"> * 3、指定拦截规则[如果是拦截所有,静态资源也会被拦截]</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AdminWebConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addInterceptors</span><span class="params">(InterceptorRegistry registry)</span> &#123;</span><br><span class="line"> registry.addInterceptor(<span class="keyword">new</span> <span class="title class_">LoginInterceptor</span>())</span><br><span class="line"> .addPathPatterns(<span class="string">&quot;/**&quot;</span>) <span class="comment">//所有请求都被拦截包括静态资源</span></span><br><span class="line"> .excludePathPatterns(<span class="string">&quot;/&quot;</span>,<span class="string">&quot;/login&quot;</span>,<span class="string">&quot;/css/**&quot;</span>,<span class="string">&quot;/fonts/**&quot;</span>,<span class="string">&quot;/images/**&quot;</span>,<span class="string">&quot;/js/**&quot;</span>); <span class="comment">//放行的请求</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-拦截器原理"><a href="#3-拦截器原理" class="headerlink" title="3.拦截器原理"></a>3.拦截器原理</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * preHandle() :该方法在控制器方法之前执行如果返回false,说明拦截器不放行该请求,自己处理或者结束该请求</span></span><br><span class="line"><span class="comment"> * 如果返回true说明拦截器放该请求由其它匹配的拦截器或者控制器继续处理</span></span><br><span class="line"><span class="comment"> * postHandle():该方法在控制器方法调用之后,且解析视图之前执行,可以通过此方法对请求域中的模型和视图做出进一步的修改</span></span><br><span class="line"><span class="comment"> * afterCompletion() 该方法会在整个请求完成,即视图渲染结束之后执行,多用于资源的清理工作</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>
<p>1、根据当前请求找到HandlerExecutionChain[可以处理请求的handler以及handler的所有 拦截器]</p>
<p>2、先来顺序执行 所有拦截器的 preHandle方法</p>
<ul>
<li>1、如果当前拦截器prehandler返回为true,则执行下一个拦截器的preHandle</li>
<li>2、如果当前拦截器返回为false。直接倒序执行所有已经执行了的拦截器的afterCompletion方法</li>
</ul>
<p>3、如果任何一个拦截器返回false直接跳出不执行目标方法</p>
<p>4、所有拦截器都返回true,执行目标方法</p>
<p>5、倒序执行所有拦截器的postHandle方法</p>
<p>6、前面的步骤有任何异常都会直接倒序触发 afterCompletion</p>
<p>7、页面成功渲染完成以后也会倒序触发 afterCompletion</p>
<p><img src="/pictures/image-20230821112246355.png" alt="image-20230821112246355"></p>
<h3 id="5-文件上传"><a href="#5-文件上传" class="headerlink" title="5.文件上传"></a>5.文件上传</h3><h4 id="1-页面表单"><a href="#1-页面表单" class="headerlink" title="1.页面表单"></a>1.页面表单</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span> <span class="attr">action</span>=<span class="string">&quot;/upload&quot;</span> <span class="attr">enctype</span>=<span class="string">&quot;multipart/form-data&quot;</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;file&quot;</span> <span class="attr">name</span>=<span class="string">&quot;file&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;提交&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="2-文件上传代码"><a href="#2-文件上传代码" class="headerlink" title="2.文件上传代码"></a>2.文件上传代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * MultipartFile 自动封装上传过来的文件</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">upload</span><span class="params">(<span class="meta">@RequestParam(&quot;email&quot;)</span> String email,</span></span><br><span class="line"><span class="params"> <span class="meta">@RequestParam(&quot;username&quot;)</span> String username,</span></span><br><span class="line"><span class="params"> <span class="meta">@RequestPart(&quot;headerImg&quot;)</span> MultipartFile headerImg,//单个文件</span></span><br><span class="line"><span class="params"> <span class="meta">@RequestPart(&quot;photos&quot;)</span> MultipartFile[] photos)</span> <span class="keyword">throws</span> IOException &#123;<span class="comment">//多个文件</span></span><br><span class="line"></span><br><span class="line"> log.info(<span class="string">&quot;上传的信息email=&#123;&#125;username=&#123;&#125;headerImg=&#123;&#125;photos=&#123;&#125;&quot;</span>,</span><br><span class="line"> email, username, headerImg.getSize(), photos.length);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!headerImg.isEmpty()) &#123;</span><br><span class="line"> <span class="comment">//保存到文件服务器OSS服务器</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">originalFilename</span> <span class="operator">=</span> headerImg.getOriginalFilename();</span><br><span class="line"> headerImg.transferTo(<span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;H:\\cache\\&quot;</span> + originalFilename));</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (photos.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line"> <span class="keyword">for</span> (MultipartFile photo : photos) &#123;</span><br><span class="line"> <span class="keyword">if</span> (!photo.isEmpty()) &#123;</span><br><span class="line"> <span class="type">String</span> <span class="variable">originalFilename</span> <span class="operator">=</span> photo.getOriginalFilename();</span><br><span class="line"> photo.transferTo(<span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;H:\\cache\\&quot;</span> + originalFilename));</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;main&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-MultipartAutoConfiguration"><a href="#3-MultipartAutoConfiguration" class="headerlink" title="3.MultipartAutoConfiguration"></a>3.MultipartAutoConfiguration</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123; Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class &#125;)</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(prefix = &quot;spring.servlet.multipart&quot;, name = &quot;enabled&quot;, matchIfMissing = true)</span></span><br><span class="line"><span class="meta">@ConditionalOnWebApplication(type = Type.SERVLET)</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(MultipartProperties.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MultipartAutoConfiguration</span> &#123;&#125;</span><br></pre></td></tr></table></figure>
<h3 id="6-异常处理"><a href="#6-异常处理" class="headerlink" title="6.异常处理"></a>6.异常处理</h3><p>开发中异常处理方法: <a href="https://qingling.icu/posts/31385.html">https://qingling.icu/posts/31385.html</a></p>
<h4 id="1-默认规则"><a href="#1-默认规则" class="headerlink" title="1.默认规则"></a>1.默认规则</h4><ul>
<li>默认情况下Spring Boot提供<code>/error</code>处理所有错误的映射</li>
<li>对于机器客户端它将生成JSON响应其中包含错误HTTP状态和异常消息的详细信息。对于浏览器客户端响应一个“ whitelabel”错误视图以HTML格式呈现相同的数据</li>
</ul>
<h4 id="2-自定义错误页面"><a href="#2-自定义错误页面" class="headerlink" title="2.自定义错误页面"></a>2.自定义错误页面</h4><p>templates&#x2F;error&#x2F;下的4xx5xx页面会被自动解析</p>
<h3 id="7-Web原生组件注入Servlet、Filter、Listener"><a href="#7-Web原生组件注入Servlet、Filter、Listener" class="headerlink" title="7.Web原生组件注入Servlet、Filter、Listener"></a>7.Web原生组件注入Servlet、Filter、Listener</h3><h4 id="7-1-使用Servlet-Api"><a href="#7-1-使用Servlet-Api" class="headerlink" title="7.1 使用Servlet Api"></a>7.1 使用Servlet Api</h4><h5 id="1-原生的Servlet的使用"><a href="#1-原生的Servlet的使用" class="headerlink" title="1.原生的Servlet的使用"></a>1.原生的Servlet的使用</h5><p>1.编写自定义的servlet继承HttpServlet</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.servlet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletException;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.WebServlet;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServlet;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletResponse;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/26</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@WebServlet(urlPatterns = &quot;/my&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyServlet</span> <span class="keyword">extends</span> <span class="title class_">HttpServlet</span> &#123;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doGet</span><span class="params">(HttpServletRequest req, HttpServletResponse resp)</span> <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line"> resp.getWriter().write(<span class="string">&quot;6666&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>2.在启动类上添加自定义servlet的包扫描注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.servlet.ServletComponentScan;</span><br><span class="line"></span><br><span class="line"><span class="meta">@ServletComponentScan(&quot;com.atguigu.boot&quot;)</span> <span class="comment">//指定原生的servlet的位置</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Boot05Web01Application</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"> SpringApplication.run(Boot05Web01Application.class, args);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>3.启动程序测试</p>
<p><img src="/pictures/image-20230826211541424.png" alt="image-20230826211541424"></p>
<h5 id="2-原生的Filter的使用"><a href="#2-原生的Filter的使用" class="headerlink" title="2.原生的Filter的使用"></a>2.原生的Filter的使用</h5><p>1.编写自定义的Filter实现Filter接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.servlet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.*;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.WebFilter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/26</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@WebFilter(urlPatterns=&#123;&quot;/css/*&quot;,&quot;/images/*&quot;,&quot;/my&quot;&#125;)</span> <span class="comment">//设置拦截的路径</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyFilter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line"> log.info(<span class="string">&quot;MyFilter初始化完成&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest request, ServletResponse response, FilterChain chain)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line"> log.info(<span class="string">&quot;MyFilter工作&quot;</span>);</span><br><span class="line"> chain.doFilter(request,response);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;MyFilter销毁&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>2.启动程序测试</p>
<p><img src="/pictures/image-20230826212400849.png" alt="image-20230826212400849"></p>
<h5 id="3-原生的Listener的使用"><a href="#3-原生的Listener的使用" class="headerlink" title="3.原生的Listener的使用"></a>3.原生的Listener的使用</h5><p>1.编写自定义的MyServletContextListener实现ServletContextListener</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.servlet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletContextEvent;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletContextListener;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.WebListener;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/26</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@WebListener</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyServletContextListener</span> <span class="keyword">implements</span> <span class="title class_">ServletContextListener</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contextInitialized</span><span class="params">(ServletContextEvent sce)</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;MyServletContextListener监听到项目初始化完成&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contextDestroyed</span><span class="params">(ServletContextEvent sce)</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;MyServletContextListener监听到项目销毁&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>2.启动程序测试</p>
<p><img src="/pictures/image-20230826213125490.png" alt="image-20230826213125490"></p>
<h4 id="7-2-使用RegistrationBean"><a href="#7-2-使用RegistrationBean" class="headerlink" title="7.2 使用RegistrationBean"></a>7.2 使用RegistrationBean</h4><p>不使用@WebServlet、@WebFilter、@WebListener注解的方式(注释掉自定义servlet、Filter、Listener上的注解)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.servlet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.servlet.FilterRegistrationBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.servlet.ServletListenerRegistrationBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.web.servlet.ServletRegistrationBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/26</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyRegisterConfig</span> &#123;</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> ServletRegistrationBean <span class="title function_">myServlet</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="type">MyServlet</span> <span class="variable">myServlet</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyServlet</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ServletRegistrationBean</span>(myServlet,<span class="string">&quot;/my&quot;</span>,<span class="string">&quot;/my02&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> FilterRegistrationBean <span class="title function_">myFilter</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">MyFilter</span> <span class="variable">myFilter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyFilter</span>();</span><br><span class="line"> <span class="comment">//return new FilterRegistrationBean(myFilter,myServlet());</span></span><br><span class="line"> <span class="type">FilterRegistrationBean</span> <span class="variable">filterRegistrationBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FilterRegistrationBean</span>(myFilter);</span><br><span class="line"> filterRegistrationBean.setUrlPatterns(Arrays.asList(<span class="string">&quot;/my&quot;</span>,<span class="string">&quot;/css/*&quot;</span>));</span><br><span class="line"> <span class="keyword">return</span> filterRegistrationBean;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> ServletListenerRegistrationBean <span class="title function_">myListener</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="type">MyServletContextListener</span> <span class="variable">mySwervletContextListener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyServletContextListener</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ServletListenerRegistrationBean</span>(mySwervletContextListener);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>重新启动项目我们可以看到依然生效</p>
<p><img src="/pictures/image-20230826214253187.png" alt="image-20230826214253187"></p>
<h3 id="8-嵌入式Servlet容器"><a href="#8-嵌入式Servlet容器" class="headerlink" title="8.嵌入式Servlet容器"></a>8.嵌入式Servlet容器</h3><h4 id="8-1-切换嵌入式Servlet容器"><a href="#8-1-切换嵌入式Servlet容器" class="headerlink" title="8.1 切换嵌入式Servlet容器"></a>8.1 切换嵌入式Servlet容器</h4><ul>
<li><p>默认支持的webServer</p>
</li>
<li><ul>
<li><code>Tomcat</code>, <code>Jetty</code>, or <code>Undertow</code></li>
<li><code>ServletWebServerApplicationContext 容器启动寻找ServletWebServerFactory 并引导创建服务器</code></li>
</ul>
</li>
<li><p>切换服务器</p>
<p>1.排除tomcat的依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2.引入需要的服务器场景</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-undertow<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>3.重启项目可以看到服务器由tomcat变成了undertow</p>
<p><img src="/pictures/image-20230826221229898.png" alt="image-20230826221229898"></p>
</li>
<li><p>原理</p>
</li>
<li><ul>
<li>SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat</li>
<li>web应用会创建一个web版的ioc容器 <code>ServletWebServerApplicationContext</code> </li>
<li><code>ServletWebServerApplicationContext</code> 启动的时候寻找 <code>**ServletWebServerFactory**``Servlet 的web服务器工厂---&gt; Servlet 的web服务器</code> </li>
<li>SpringBoot底层默认有很多的WebServer工厂<code>TomcatServletWebServerFactory</code>, <code>JettyServletWebServerFactory</code>, or <code>UndertowServletWebServerFactory</code></li>
<li><code>底层直接会有一个自动配置类ServletWebServerFactoryAutoConfiguration</code></li>
<li><code>ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration配置类</code></li>
<li><code>ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包默认是web-starter导入tomcat包容器中就有 TomcatServletWebServerFactory</code></li>
<li><code>TomcatServletWebServerFactory 创建出Tomcat服务器并启动TomcatWebServer 的构造器拥有初始化方法initialize---this.tomcat.start();</code></li>
<li><code>内嵌服务器就是手动把启动服务器的代码调用tomcat核心jar包存在</code></li>
</ul>
</li>
</ul>
<h4 id="8-2-定制Servlet容器"><a href="#8-2-定制Servlet容器" class="headerlink" title="8.2 定制Servlet容器"></a>8.2 定制Servlet容器</h4><p>修改配置文件中以server.xxx打头的属性信息</p>
<p><img src="/pictures/image-20230826222050817.png" alt="image-20230826222050817"></p>
<h2 id="三-数据访问"><a href="#三-数据访问" class="headerlink" title="三.数据访问"></a>三.数据访问</h2><h3 id="1-SQL"><a href="#1-SQL" class="headerlink" title="1.SQL"></a>1.SQL</h3><h4 id="1-1-JDBC的使用"><a href="#1-1-JDBC的使用" class="headerlink" title="1.1 JDBC的使用"></a>1.1 JDBC的使用</h4><p>1.导入JDBC的场景</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2.导入自己使用的数据库的驱动Mysql或者Oracle版本号不写也可以官方做了版本仲裁但是要与实际安装的版本对应</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">想要修改版本</span><br><span class="line">1、直接依赖引入具体版本maven的就近依赖原则</span><br><span class="line">2、重新声明版本maven的属性的就近优先原则</span><br><span class="line"><span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">mysql.version</span>&gt;</span>5.1.45<span class="tag">&lt;/<span class="name">mysql.version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">或者</span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.1.45<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>3.添加配置</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">datasource:</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">jdbc:mysql://localhost:3306/db_account</span></span><br><span class="line"> <span class="attr">username:</span> <span class="string">root</span></span><br><span class="line"> <span class="attr">password:</span> <span class="number">123456</span></span><br><span class="line"> <span class="attr">driver-class-name:</span> <span class="string">com.mysql.jdbc.Driver</span></span><br><span class="line"> <span class="comment"># type: com.zaxxer.hikari.HikariDataSource #配置数据源</span></span><br></pre></td></tr></table></figure>
<p>4.测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Boot05Web01ApplicationTests</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> JdbcTemplate jdbcTemplate;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">contextLoads</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="type">Long</span> <span class="variable">count</span> <span class="operator">=</span> jdbcTemplate.queryForObject(<span class="string">&quot;select count(*) from `role` &quot;</span>, Long.class);</span><br><span class="line"> log.info(<span class="string">&quot;记录数:&#123;&#125;&quot;</span>,count);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="1-2-分析自动配置"><a href="#1-2-分析自动配置" class="headerlink" title="1.2 分析自动配置"></a>1.2 分析自动配置</h4><p><strong>自动配置的类</strong></p>
<p><img src="/pictures/image-20230826224503510.png" alt="image-20230826224503510"></p>
<ul>
<li><p>DataSourceAutoConfiguration 数据源的自动配置</p>
</li>
<li><ul>
<li>修改数据源相关的配置spring.datasource</li>
<li>数据库连接池的配置是自己容器中没有DataSource才自动配置的</li>
<li>底层配置好的连接池是HikariDataSource</li>
</ul>
</li>
<li><p>DataSourceTransactionManagerAutoConfiguration 事务管理器的自动配置</p>
</li>
<li><p>JdbcTemplateAutoConfiguration JdbcTemplate的自动配置可以来对数据库进行crud</p>
</li>
<li><ul>
<li>可以修改这个配置项@ConfigurationProperties(prefix &#x3D; “spring.jdbc”) 来修改JdbcTemplate</li>
</ul>
</li>
<li><p>JndiDataSourceAutoConfiguration jndi的自动配置</p>
</li>
<li><p>XADataSourceAutoConfiguration 分布式事务相关的</p>
</li>
</ul>
<h2 id="四-单元测试"><a href="#四-单元测试" class="headerlink" title="四.单元测试"></a>四.单元测试</h2><h3 id="1-JUnit5的变化"><a href="#1-JUnit5的变化" class="headerlink" title="1.JUnit5的变化"></a>1.JUnit5的变化</h3><p><strong>Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库</strong></p>
<p>作为最新版本的JUnit框架JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成</p>
<p>JUnit 5 &#x3D; JUnit Platform + JUnit Jupiter + JUnit Vintage</p>
<p>JUnit Platform: Junit Platform是在JVM上启动测试框架的基础不仅支持Junit自制的测试引擎其他测试引擎也都可以接入</p>
<p>JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型是JUnit5新特性的核心。内部 包含了一个测试引擎用于在Junit Platform上运行</p>
<p>JUnit Vintage: 由于JUint已经发展多年为了照顾老的项目JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎</p>
<p><strong>注意:</strong></p>
<p>SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入不能使用junit4的功能 @Test</p>
<p><strong>以前的版本</strong></p>
<p>兼容以前的版本(junit4)需要额外导入的依赖(SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖)</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.junit.vintage<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit-vintage-engine<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.hamcrest<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>hamcrest-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>标注的注解</p>
<p>@SpringBootTest + @RunWith(SpringRunner.class)+@Test(4版本的@Test)</p>
<p><strong>现在的版本</strong></p>
<p>需要导入的依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>标注的注解</p>
<p>@SpringBootTest + @Test</p>
<p><strong>两个不同版本的 @Test 注解</strong></p>
<p><img src="/pictures/image-20230827112742347.png" alt="image-20230827112742347"></p>
<h3 id="2-JUnit5常用注解"><a href="#2-JUnit5常用注解" class="headerlink" title="2.JUnit5常用注解"></a>2.JUnit5常用注解</h3><p>JUnit5的注解与JUnit4的注解有所变化</p>
<p><a target="_blank" rel="noopener" href="https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations">https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations</a></p>
<ul>
<li>@Test :表示方法是测试方法。但是与JUnit4的@Test不同他的职责非常单一不能声明任何属性拓展的测试将会由Jupiter提供额外测试</li>
<li>@ParameterizedTest :表示方法是参数化测试,下方会有详细介绍</li>
<li>@RepeatedTest :表示方法可重复执行,下方会有详细介绍</li>
<li>@DisplayName :为测试类或者测试方法设置展示名称</li>
</ul>
<p><img src="/pictures/image-20230827114256749.png" alt="image-20230827114256749"></p>
<ul>
<li><p>@BeforeEach :表示在每个单元测试之前执行</p>
</li>
<li><p>@AfterEach :表示在每个单元测试之后执行</p>
</li>
<li><p>@BeforeAll :表示在所有单元测试之前执行</p>
</li>
<li><p>@AfterAll :表示在所有单元测试之后执行</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/27</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 测试junit5的相关注解</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;Junit5Test测试类&quot;)</span></span><br><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Junit5Test</span> &#123;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@DisplayName</span> 加在方法或者类上,为测试类或者测试方法设置展示名称</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Disabled</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;测试@DisplayName注解&quot;)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testDisplayName</span><span class="params">()</span>&#123;</span><br><span class="line"> log.info(<span class="string">&quot;@DisplayName注解的测试&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在执行的单元测试方法之前运行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@BeforeEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testBeforeEach</span><span class="params">()</span>&#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testBeforeEach()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在执行的单元测试方法之后运行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@AfterEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testAfterEach</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testAfterEach()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在所有的单元测试执行之后执行</span></span><br><span class="line"><span class="comment"> * 注意是静态方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@BeforeAll</span></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testBeforeAll</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testBeforeAll()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在所有的单元测试执行之前执行</span></span><br><span class="line"><span class="comment"> * 注意是静态方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@AfterAll</span></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testAfterAll</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testAfterAll()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>@Tag :表示单元测试类别类似于JUnit4中的@Categories</li>
<li>@Disabled :表示测试类或测试方法不执行类似于JUnit4中的@Ignore</li>
</ul>
<p><img src="/pictures/image-20230827115900097.png" alt="image-20230827115900097"></p>
<ul>
<li>@Timeout :表示测试方法运行如果超过了指定时间将会返回错误</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 规定方法超时时间 超出时间测试出异常</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">testTimeout</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line"> Thread.sleep(<span class="number">600</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>@ExtendWith :为测试类或测试方法提供扩展类引用</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 重复测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@RepeatedTest(5)</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">testRepeatedTest</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;重复测试中&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230828095915653.png" alt="image-20230828095915653"></p>
<p><strong>全部的代码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Jason Gong</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@website</span> https://qingling.icu</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2023/8/27</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 测试junit5的相关注解</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;Junit5Test测试类&quot;)</span></span><br><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Junit5Test</span> &#123;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@DisplayName</span> 加在方法或者类上,为测试类或者测试方法设置展示名称</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Disabled</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;测试@DisplayName注解&quot;)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testDisplayName</span><span class="params">()</span>&#123;</span><br><span class="line"> log.info(<span class="string">&quot;@DisplayName注解的测试&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在执行的单元测试方法之前运行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@BeforeEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testBeforeEach</span><span class="params">()</span>&#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testBeforeEach()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在执行的单元测试方法之后运行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@AfterEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testAfterEach</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testAfterEach()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在所有的单元测试执行之后执行</span></span><br><span class="line"><span class="comment"> * 注意是静态方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@BeforeAll</span></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testBeforeAll</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testBeforeAll()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 在所有的单元测试执行之前执行</span></span><br><span class="line"><span class="comment"> * 注意是静态方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@AfterAll</span></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testAfterAll</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;执行了testAfterAll()方法&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 规定方法超时时间 超出时间测试出异常</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testTimeout</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line"> Thread.sleep(<span class="number">600</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 重复测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@RepeatedTest(5)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testRepeatedTest</span><span class="params">()</span> &#123;</span><br><span class="line"> log.info(<span class="string">&quot;重复测试中&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-断言"><a href="#3-断言" class="headerlink" title="3.断言"></a>3.断言</h3><p> 断言assertions是测试方法中的核心部分用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。检查业务逻辑返回的数据是否合理。所有的测试运行结束以后,会有一个详细的测试报告。</p>
<h4 id="3-1-简单断言"><a href="#3-1-简单断言" class="headerlink" title="3.1 简单断言"></a>3.1 简单断言</h4><p>用来对单个值进行简单的验证</p>
<table>
<thead>
<tr>
<th>方法</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>assertEquals</td>
<td>判断两个对象或两个原始类型是否相等</td>
</tr>
<tr>
<td>assertNotEquals</td>
<td>判断两个对象或两个原始类型是否不相等</td>
</tr>
<tr>
<td>assertSame</td>
<td>判断两个对象引用是否指向同一个对象</td>
</tr>
<tr>
<td>assertNotSame</td>
<td>判断两个对象引用是否指向不同的对象</td>
</tr>
<tr>
<td>assertTrue</td>
<td>判断给定的布尔值是否为 true</td>
</tr>
<tr>
<td>assertFalse</td>
<td>判断给定的布尔值是否为 false</td>
</tr>
<tr>
<td>assertNull</td>
<td>判断给定的对象引用是否为 null</td>
</tr>
<tr>
<td>assertNotNull</td>
<td>判断给定的对象引用是否不为 null</td>
</tr>
</tbody></table>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;简单断言&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">simple</span><span class="params">()</span> &#123;</span><br><span class="line"> assertEquals(<span class="number">3</span>, <span class="number">1</span> + <span class="number">2</span>, <span class="string">&quot;simple math&quot;</span>);</span><br><span class="line"> assertNotEquals(<span class="number">3</span>, <span class="number">1</span> + <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> assertNotSame(<span class="keyword">new</span> <span class="title class_">Object</span>(), <span class="keyword">new</span> <span class="title class_">Object</span>());</span><br><span class="line"> <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line"> assertSame(obj, obj);</span><br><span class="line"></span><br><span class="line"> assertFalse(<span class="number">1</span> &gt; <span class="number">2</span>);</span><br><span class="line"> assertTrue(<span class="number">1</span> &lt; <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"> assertNull(<span class="literal">null</span>);</span><br><span class="line"> assertNotNull(<span class="keyword">new</span> <span class="title class_">Object</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-数组断言"><a href="#3-2-数组断言" class="headerlink" title="3.2 数组断言"></a>3.2 数组断言</h4><p>通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;数组断言&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">array</span><span class="params">()</span> &#123;</span><br><span class="line"> assertArrayEquals(<span class="keyword">new</span> <span class="title class_">int</span>[]&#123;<span class="number">1</span>, <span class="number">2</span>&#125;, <span class="keyword">new</span> <span class="title class_">int</span>[] &#123;<span class="number">1</span>, <span class="number">2</span>&#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-3-组合断言"><a href="#3-3-组合断言" class="headerlink" title="3.3 组合断言"></a>3.3 组合断言</h4><p>assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;组合断言&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">all</span><span class="params">()</span> &#123;</span><br><span class="line"> assertAll(<span class="string">&quot;Math&quot;</span>,</span><br><span class="line"> () -&gt; assertEquals(<span class="number">2</span>, <span class="number">1</span> + <span class="number">1</span>),</span><br><span class="line"> () -&gt; assertTrue(<span class="number">1</span> &gt; <span class="number">0</span>)</span><br><span class="line"> );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-4-异常断言"><a href="#3-4-异常断言" class="headerlink" title="3.4 异常断言"></a>3.4 异常断言</h4><p>在JUnit4时期想要测试方法的异常情况时需要用@Rule注解的ExpectedException变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;异常测试&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">exceptionTest</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="type">ArithmeticException</span> <span class="variable">exception</span> <span class="operator">=</span> Assertions.assertThrows(</span><br><span class="line"> <span class="comment">//扔出断言异常</span></span><br><span class="line"> ArithmeticException.class, () -&gt; System.out.println(<span class="number">1</span> % <span class="number">0</span>));</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-5-超时断言"><a href="#3-5-超时断言" class="headerlink" title="3.5 超时断言"></a>3.5 超时断言</h4><p>Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;超时测试&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">timeoutTest</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="comment">//如果测试方法时间超过1s将会异常</span></span><br><span class="line"> Assertions.assertTimeout(Duration.ofMillis(<span class="number">1000</span>), () -&gt; Thread.sleep(<span class="number">500</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-6-快速失败"><a href="#3-6-快速失败" class="headerlink" title="3.6 快速失败"></a>3.6 快速失败</h4><p>通过 fail 方法直接使得测试失败</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;快速失败&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">shouldFail</span><span class="params">()</span> &#123;</span><br><span class="line"> fail(<span class="string">&quot;This should fail&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>全部代码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.admin;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.*;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.jdbc.core.JdbcTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> org.junit.jupiter.api.Assertions.*;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*@RunWith*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@BootstrapWith</span>(SpringBootTestContextBootstrapper.class)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ExtendWith</span>(SpringExtension.class)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//@SpringBootTest</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;junit5功能测试类&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Junit5Test</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 断言:前面断言失败,后面的代码都不会执行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;简单断言&quot;)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testSimpleAssertions</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="type">int</span> <span class="variable">cal</span> <span class="operator">=</span> cal(<span class="number">3</span>, <span class="number">2</span>);</span><br><span class="line"> <span class="comment">//相等</span></span><br><span class="line"> assertEquals(<span class="number">6</span>, cal, <span class="string">&quot;业务逻辑计算失败&quot;</span>);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">obj1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line"> <span class="type">Object</span> <span class="variable">obj2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line"> assertSame(obj1, obj2, <span class="string">&quot;两个对象不一样&quot;</span>);</span><br><span class="line"></span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;数组断言&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">array</span><span class="params">()</span> &#123;</span><br><span class="line"> assertArrayEquals(<span class="keyword">new</span> <span class="title class_">int</span>[]&#123;<span class="number">1</span>, <span class="number">2</span>&#125;, <span class="keyword">new</span> <span class="title class_">int</span>[]&#123;<span class="number">1</span>, <span class="number">2</span>&#125;, <span class="string">&quot;数组内容不相等&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;组合断言&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">all</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 所有断言全部需要成功</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> assertAll(<span class="string">&quot;test&quot;</span>,</span><br><span class="line"> () -&gt; assertTrue(<span class="literal">true</span> &amp;&amp; <span class="literal">true</span>, <span class="string">&quot;结果不为true&quot;</span>),</span><br><span class="line"> () -&gt; assertEquals(<span class="number">1</span>, <span class="number">2</span>, <span class="string">&quot;结果不是1&quot;</span>));</span><br><span class="line"></span><br><span class="line"> System.out.println(<span class="string">&quot;=====&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@DisplayName(&quot;异常断言&quot;)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testException</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//断定业务逻辑一定出现异常</span></span><br><span class="line"> assertThrows(ArithmeticException.class, () -&gt; &#123;</span><br><span class="line"> <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">10</span> / <span class="number">2</span>;</span><br><span class="line"> &#125;, <span class="string">&quot;业务逻辑居然正常运行?&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@DisplayName(&quot;快速失败&quot;)</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">testFail</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(<span class="number">1</span> == <span class="number">2</span>)&#123;</span><br><span class="line"> fail(<span class="string">&quot;测试失败&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"> <span class="type">int</span> <span class="title function_">cal</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> i + j;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-前置条件"><a href="#4-前置条件" class="headerlink" title="4.前置条件"></a>4.前置条件</h3><p> JUnit 5 中的前置条件assumptions[假设])类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@DisplayName(&quot;前置条件&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AssumptionsTest</span> &#123;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">environment</span> <span class="operator">=</span> <span class="string">&quot;DEV&quot;</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;simple&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">simpleAssume</span><span class="params">()</span> &#123;</span><br><span class="line"> assumeTrue(Objects.equals(<span class="built_in">this</span>.environment, <span class="string">&quot;DEV&quot;</span>));</span><br><span class="line"> assumeFalse(() -&gt; Objects.equals(<span class="built_in">this</span>.environment, <span class="string">&quot;PROD&quot;</span>));</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;assume then do&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">assumeThenDo</span><span class="params">()</span> &#123;</span><br><span class="line"> assumingThat(</span><br><span class="line"> Objects.equals(<span class="built_in">this</span>.environment, <span class="string">&quot;DEV&quot;</span>),</span><br><span class="line"> () -&gt; System.out.println(<span class="string">&quot;In DEV&quot;</span>)</span><br><span class="line"> );</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>assumeTrue 和 assumFalse 确保给定的条件为 true 或 false不满足条件会使得测试执行终止</p>
<p>assumingThat 的参数是表示条件的布尔值和对应的 Executable 接口的实现对象</p>
<p>只有条件满足时Executable 对象才会被执行;当条件不满足时,测试执行并不会终止</p>
<h3 id="5-嵌套测试"><a href="#5-嵌套测试" class="headerlink" title="5.嵌套测试"></a>5.嵌套测试</h3><p> JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@DisplayName(&quot;A stack&quot;)</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TestingAStackDemo</span> &#123;</span><br><span class="line"></span><br><span class="line"> Stack&lt;Object&gt; stack;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;is instantiated with new Stack()&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">isInstantiatedWithNew</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Stack</span>&lt;&gt;();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Nested</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;when new&quot;)</span></span><br><span class="line"> <span class="keyword">class</span> <span class="title class_">WhenNew</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@BeforeEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">createNewStack</span><span class="params">()</span> &#123;</span><br><span class="line"> stack = <span class="keyword">new</span> <span class="title class_">Stack</span>&lt;&gt;();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;is empty&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;</span><br><span class="line"> assertTrue(stack.isEmpty());</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;throws EmptyStackException when popped&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">throwsExceptionWhenPopped</span><span class="params">()</span> &#123;</span><br><span class="line"> assertThrows(EmptyStackException.class, stack::pop);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;throws EmptyStackException when peeked&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">throwsExceptionWhenPeeked</span><span class="params">()</span> &#123;</span><br><span class="line"> assertThrows(EmptyStackException.class, stack::peek);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Nested</span><span class="comment">//b</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;after pushing an element&quot;)</span></span><br><span class="line"> <span class="keyword">class</span> <span class="title class_">AfterPushing</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">anElement</span> <span class="operator">=</span> <span class="string">&quot;an element&quot;</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@BeforeEach</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">pushAnElement</span><span class="params">()</span> &#123;</span><br><span class="line"> stack.push(anElement);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;it is no longer empty&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">isNotEmpty</span><span class="params">()</span> &#123;</span><br><span class="line"> assertFalse(stack.isEmpty());</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;returns the element when popped and is empty&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">returnElementWhenPopped</span><span class="params">()</span> &#123;</span><br><span class="line"> assertEquals(anElement, stack.pop());</span><br><span class="line"> assertTrue(stack.isEmpty());</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="meta">@DisplayName(&quot;returns the element when peeked but remains not empty&quot;)</span></span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">returnElementWhenPeeked</span><span class="params">()</span> &#123;</span><br><span class="line"> assertEquals(anElement, stack.peek());</span><br><span class="line"> assertFalse(stack.isEmpty());</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="6-参数化测试"><a href="#6-参数化测试" class="headerlink" title="6.参数化测试"></a>6.参数化测试</h3><p>参数化测试是JUnit5很重要的一个新特性它使得用不同的参数多次运行测试成为了可能也为我们的单元测试带来许多便利</p>
<p>利用@ValueSource等注解指定入参我们将可以使用不同的参数进行多次单元测试而不需要每新增一个参数就新增一个单元测试省去了很多冗余代码</p>
<p>@ValueSource: 为参数化测试指定入参来源支持八大基础类以及String类型,Class类型</p>
<p>@NullSource: 表示为参数化测试提供一个null的入参</p>
<p>@EnumSource: 表示为参数化测试提供一个枚举入参</p>
<p>@CsvFileSource表示读取指定CSV文件内容作为参数化测试入参</p>
<p>@MethodSource表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)</p>
<p>当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。让我真正感到他的强大之处的地方在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现ArgumentsProvider接口任何外部文件都可以作为它的入参</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ParameterizedTest</span></span><br><span class="line"><span class="meta">@ValueSource(strings = &#123;&quot;one&quot;, &quot;two&quot;, &quot;three&quot;&#125;)</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;参数化测试&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">parameterizedTest</span><span class="params">(String string)</span> &#123;</span><br><span class="line"> System.out.println(string);</span><br><span class="line"> Assertions.assertTrue(StringUtils.isNotBlank(string));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@ParameterizedTest</span></span><br><span class="line"><span class="meta">@MethodSource(&quot;method&quot;)</span> <span class="comment">//指定方法名</span></span><br><span class="line"><span class="meta">@DisplayName(&quot;方法来源参数&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testWithExplicitLocalMethodSource</span><span class="params">(String name)</span> &#123;<span class="comment">//方法的参数来源于一个方法</span></span><br><span class="line"> System.out.println(name);</span><br><span class="line"> Assertions.assertNotNull(name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> Stream&lt;String&gt; <span class="title function_">method</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> Stream.of(<span class="string">&quot;apple&quot;</span>, <span class="string">&quot;banana&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="7-迁移指南"><a href="#7-迁移指南" class="headerlink" title="7.迁移指南"></a>7.迁移指南</h3><p>在进行迁移Junit4迁移到Junit5的时候需要注意如下的变化</p>
<ul>
<li>注解在 org.junit.jupiter.api 包中,断言在 org.junit.jupiter.api.Assertions 类中,前置条件在 org.junit.jupiter.api.Assumptions 类中。</li>
<li>把@Before 和@After 替换成@BeforeEach 和@AfterEach。</li>
<li>把@BeforeClass 和@AfterClass 替换成@BeforeAll 和@AfterAll。</li>
<li>把@Ignore 替换成@Disabled。</li>
<li>把@Category 替换成@Tag。</li>
<li>把@RunWith、@Rule 和@ClassRule 替换成@ExtendWith。</li>
</ul>
<h2 id="五-指标监控"><a href="#五-指标监控" class="headerlink" title="五.指标监控"></a>五.指标监控</h2><h3 id="1-SpringBoot-Actuator"><a href="#1-SpringBoot-Actuator" class="headerlink" title="1.SpringBoot Actuator"></a>1.SpringBoot Actuator</h3><p> 未来每一个微服务在云上部署以后我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能</p>
<h4 id="1-1-如何使用"><a href="#1-1-如何使用" class="headerlink" title="1.1 如何使用"></a>1.1 如何使用</h4><p>1.引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>2.测试访问 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/">http://localhost:8080/actuator/</a> endpoint节点</p>
<p><img src="/pictures/image-20230828110908056.png" alt="image-20230828110908056"></p>
<p><img src="/pictures/image-20230828110928951.png" alt="image-20230828110928951"></p>
<p>3.设置以web的方式访问所有的端点</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">management:</span></span><br><span class="line"> <span class="attr">endpoints:</span></span><br><span class="line"> <span class="attr">enabled-by-default:</span> <span class="literal">true</span> <span class="comment">#暴露所有端点信息</span></span><br><span class="line"> <span class="attr">web:</span></span><br><span class="line"> <span class="attr">exposure:</span></span><br><span class="line"> <span class="attr">include:</span> <span class="string">&#x27;*&#x27;</span> <span class="comment">#以web方式暴露所有的端点</span></span><br></pre></td></tr></table></figure>
<p>设置之后就可以通过web访问 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/beans%EF%BC%89%E7%9A%84%E6%96%B9%E5%BC%8F%E8%AE%BF%E9%97%AEbeans%E7%AB%AF%E7%82%B9%E4%BA%86">http://localhost:8080/actuator/beans的方式访问beans端点了</a></p>
<p><img src="/pictures/image-20230828113335033.png" alt="image-20230828113335033"></p>
<p><strong>支持的暴露方式</strong></p>
<ul>
<li>HTTP(web)默认只暴露health和info Endpoint,只能访问 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/health%E5%92%8C">http://localhost:8080/actuator/health和</a> <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/info">http://localhost:8080/actuator/info</a></li>
<li>JMX如Jconsole默认暴露所有Endpoint,类似于cmd下打开jconsole可以访问下面所有的endPoints</li>
<li>除过health和info剩下的Endpoint都应该进行保护访问。如果引入SpringSecurity则会默认配置安全访问规则</li>
</ul>
<p><strong>是通过web还是jmx方式访问的端点一览表</strong></p>
<table>
<thead>
<tr>
<th>ID</th>
<th>JMX</th>
<th>Web</th>
</tr>
</thead>
<tbody><tr>
<td><code>auditevents</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>beans</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>caches</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>conditions</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>configprops</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>env</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>flyway</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>health</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>heapdump</code></td>
<td>N&#x2F;A</td>
<td>No</td>
</tr>
<tr>
<td><code>httptrace</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>info</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>integrationgraph</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>jolokia</code></td>
<td>N&#x2F;A</td>
<td>No</td>
</tr>
<tr>
<td><code>logfile</code></td>
<td>N&#x2F;A</td>
<td>No</td>
</tr>
<tr>
<td><code>loggers</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>liquibase</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>metrics</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>mappings</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>prometheus</code></td>
<td>N&#x2F;A</td>
<td>No</td>
</tr>
<tr>
<td><code>scheduledtasks</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>sessions</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>shutdown</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>startup</code></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><code>threaddump</code></td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody></table>
<h4 id="1-2-常用的EndPoints"><a href="#1-2-常用的EndPoints" class="headerlink" title="1.2 常用的EndPoints"></a>1.2 常用的EndPoints</h4><p><strong><code>http://localhost:8080/actuator/endPoint </code></strong></p>
<table>
<thead>
<tr>
<th>ID</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>auditevents</code></td>
<td>暴露当前应用程序的审核事件信息。需要一个<code>AuditEventRepository组件</code></td>
</tr>
<tr>
<td><code>beans</code></td>
<td>显示应用程序中所有Spring Bean的完整列表。</td>
</tr>
<tr>
<td><code>caches</code></td>
<td>暴露可用的缓存。</td>
</tr>
<tr>
<td><code>conditions</code></td>
<td>显示自动配置的所有条件信息,包括匹配或不匹配的原因。</td>
</tr>
<tr>
<td><code>configprops</code></td>
<td>显示所有<code>@ConfigurationProperties</code></td>
</tr>
<tr>
<td><code>env</code></td>
<td>暴露Spring的属性<code>ConfigurableEnvironment</code></td>
</tr>
<tr>
<td><code>flyway</code></td>
<td>显示已应用的所有Flyway数据库迁移。 需要一个或多个<code>Flyway</code>组件。</td>
</tr>
<tr>
<td><code>health</code></td>
<td>显示应用程序运行状况信息。</td>
</tr>
<tr>
<td><code>httptrace</code></td>
<td>显示HTTP跟踪信息默认情况下最近100个HTTP请求-响应)。需要一个<code>HttpTraceRepository</code>组件。</td>
</tr>
<tr>
<td><code>info</code></td>
<td>显示应用程序信息。</td>
</tr>
<tr>
<td><code>integrationgraph</code></td>
<td>显示Spring <code>integrationgraph</code> 。需要依赖<code>spring-integration-core</code></td>
</tr>
<tr>
<td><code>loggers</code></td>
<td>显示和修改应用程序中日志的配置。</td>
</tr>
<tr>
<td><code>liquibase</code></td>
<td>显示已应用的所有Liquibase数据库迁移。需要一个或多个<code>Liquibase</code>组件。</td>
</tr>
<tr>
<td><code>metrics</code></td>
<td>显示当前应用程序的“指标”信息。</td>
</tr>
<tr>
<td><code>mappings</code></td>
<td>显示所有<code>@RequestMapping</code>路径列表。</td>
</tr>
<tr>
<td><code>scheduledtasks</code></td>
<td>显示应用程序中的计划任务。</td>
</tr>
<tr>
<td><code>sessions</code></td>
<td>允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。</td>
</tr>
<tr>
<td><code>shutdown</code></td>
<td>使应用程序正常关闭。默认禁用。</td>
</tr>
<tr>
<td><code>startup</code></td>
<td>显示由<code>ApplicationStartup</code>收集的启动步骤数据。需要使用<code>SpringApplication</code>进行配置<code>BufferingApplicationStartup</code></td>
</tr>
<tr>
<td><code>threaddump</code></td>
<td>执行线程转储。</td>
</tr>
</tbody></table>
<p>如果您的应用程序是Web应用程序Spring MVCSpring WebFlux或Jersey则可以使用以下附加端点</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>heapdump</code></td>
<td>返回<code>hprof</code>堆转储文件。</td>
</tr>
<tr>
<td><code>jolokia</code></td>
<td>通过HTTP暴露JMX bean需要引入Jolokia不适用于WebFlux。需要引入依赖<code>jolokia-core</code></td>
</tr>
<tr>
<td><code>logfile</code></td>
<td>返回日志文件的内容(如果已设置<code>logging.file.name</code><code>logging.file.path</code>属性。支持使用HTTP<code>Range</code>标头来检索部分日志文件的内容。</td>
</tr>
<tr>
<td><code>prometheus</code></td>
<td>以Prometheus服务器可以抓取的格式公开指标。需要依赖<code>micrometer-registry-prometheus</code></td>
</tr>
</tbody></table>
<p><strong>最常用的Endpoint</strong></p>
<ul>
<li>Health监控状况</li>
<li>Metrics运行时指标</li>
<li>Loggers日志记录</li>
</ul>
<h4 id="1-3-Health-Endpoint"><a href="#1-3-Health-Endpoint" class="headerlink" title="1.3 Health Endpoint"></a>1.3 Health Endpoint</h4><p>健康检查端点我们一般用于在云平台平台会定时的检查应用的健康状况我们就需要Health Endpoint可以为平台返回当前应用的一系列组件健康状况的集合。</p>
<p>重要的几点:</p>
<ul>
<li>health endpoint返回的结果应该是一系列健康检查后的一个汇总报告</li>
<li>很多的健康检查默认已经自动配置好了比如数据库、redis等</li>
<li>可以很容易的添加自定义的健康检查机制</li>
</ul>
<p>设置显示health端点的详细信息</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">management:</span></span><br><span class="line"> <span class="attr">endpoint:</span></span><br><span class="line"> <span class="attr">health:</span></span><br><span class="line"> <span class="attr">show-details:</span> <span class="string">always</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230828142631189.png" alt="image-20230828142631189"></p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;UP&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;components&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;db&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;UP&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;details&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;database&quot;</span><span class="punctuation">:</span> <span class="string">&quot;MySQL&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;validationQuery&quot;</span><span class="punctuation">:</span> <span class="string">&quot;isValid()&quot;</span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;diskSpace&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;UP&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;details&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;total&quot;</span><span class="punctuation">:</span> <span class="number">510769754112</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;free&quot;</span><span class="punctuation">:</span> <span class="number">342642921472</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;threshold&quot;</span><span class="punctuation">:</span> <span class="number">10485760</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;exists&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;ping&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;UP&quot;</span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>
<h4 id="1-4-Metrics-Endpoint"><a href="#1-4-Metrics-Endpoint" class="headerlink" title="1.4 Metrics Endpoint"></a>1.4 Metrics Endpoint</h4><p>提供详细的、层级的、空间指标信息这些信息可以被pull主动推送或者push被动获取方式得到</p>
<ul>
<li>通过Metrics对接多种监控系统</li>
<li>简化核心Metrics开发</li>
<li>添加自定义Metrics或者扩展已有Metrics</li>
</ul>
<p>查看完整的监控指标信息 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/metrics">http://localhost:8080/actuator/metrics</a></p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;names&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.acquire&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.active&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.creation&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.idle&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.max&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.min&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.pending&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.timeout&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;hikaricp.connections.usage&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;http.server.requests&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jdbc.connections.max&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jdbc.connections.min&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.buffer.count&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.buffer.memory.used&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.buffer.total.capacity&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.classes.loaded&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.classes.unloaded&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.gc.live.data.size&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.gc.max.data.size&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.gc.memory.allocated&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.gc.memory.promoted&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.gc.pause&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.memory.committed&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.memory.max&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.memory.used&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.threads.daemon&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.threads.live&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.threads.peak&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;jvm.threads.states&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;logback.events&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;process.cpu.usage&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;process.start.time&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;process.uptime&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;system.cpu.count&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="string">&quot;system.cpu.usage&quot;</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230828143224633.png" alt="image-20230828143224633"></p>
<p>查看某一个监控指标的详细信息例如查看hikaricp.connections的详细信息 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/metrics/hikaricp.connections">http://localhost:8080/actuator/metrics/hikaricp.connections</a> </p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;hikaricp.connections&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;description&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Total connections&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;baseUnit&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;measurements&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;statistic&quot;</span><span class="punctuation">:</span> <span class="string">&quot;VALUE&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="number">10</span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;availableTags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">&#123;</span></span><br><span class="line"> <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;pool&quot;</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">&quot;values&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="string">&quot;HikariPool-1&quot;</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"> <span class="punctuation">&#125;</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>
<h4 id="1-5-管理Endpoint"><a href="#1-5-管理Endpoint" class="headerlink" title="1.5 管理Endpoint"></a>1.5 管理Endpoint</h4><p><strong>开启与禁用Endpoints</strong></p>
<ul>
<li>默认所有的Endpoint除过shutdown都是开启的。</li>
<li>需要开启或者禁用某个Endpoint 配置模式为 management.endpoint.endpointName.enabled &#x3D; true</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">management:</span></span><br><span class="line"> <span class="attr">endpoint:</span></span><br><span class="line"> <span class="attr">beans:</span> <span class="comment">#可以写health、metrics等端点</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<ul>
<li>或者禁用所有的Endpoint然后手动开启指定的Endpoint</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">management:</span></span><br><span class="line"> <span class="attr">endpoints:</span></span><br><span class="line"> <span class="attr">enabled-by-default:</span> <span class="literal">false</span> <span class="comment">#禁用所有的端点jconsole中也无法使用</span></span><br><span class="line"> <span class="attr">endpoint:</span></span><br><span class="line"> <span class="attr">beans:</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span> <span class="comment">#逐一开启端点</span></span><br><span class="line"> <span class="attr">health:</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h4 id="1-6-定制Endpoint"><a href="#1-6-定制Endpoint" class="headerlink" title="1.6 定制Endpoint"></a>1.6 定制Endpoint</h4><h5 id="1-6-1-定制health-endpoint"><a href="#1-6-1-定制health-endpoint" class="headerlink" title="1.6.1 定制health endpoint"></a>1.6.1 定制health endpoint</h5><p>1.编写MyComHealthIndicator类继承AbstractHealthIndicator</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.acutuator.health;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.health.AbstractHealthIndicator;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.health.Health;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.health.Status;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自定义端点</span></span><br><span class="line"><span class="comment"> * 类的后缀必须为HealthIndicator</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyComHealthIndicator</span> <span class="keyword">extends</span> <span class="title class_">AbstractHealthIndicator</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 真实的检查方法 检查健康的方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doHealthCheck</span><span class="params">(Health.Builder builder)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> Map&lt;String,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"> <span class="comment">// 检查完成</span></span><br><span class="line"> <span class="keyword">if</span>(<span class="number">1</span> == <span class="number">1</span>)&#123; <span class="comment">//这里我们可以编写一个业务逻辑,例如数据库是否连接成功的业务逻辑</span></span><br><span class="line"> <span class="comment">// builder.up(); //健康</span></span><br><span class="line"> builder.status(Status.UP);</span><br><span class="line"> map.put(<span class="string">&quot;count&quot;</span>,<span class="number">1</span>);</span><br><span class="line"> map.put(<span class="string">&quot;ms&quot;</span>,<span class="number">100</span>);</span><br><span class="line"> &#125;<span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="comment">//builder.down();</span></span><br><span class="line"> builder.status(Status.OUT_OF_SERVICE);</span><br><span class="line"> map.put(<span class="string">&quot;err&quot;</span>,<span class="string">&quot;连接超时&quot;</span>);</span><br><span class="line"> map.put(<span class="string">&quot;ms&quot;</span>,<span class="number">3000</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> builder.withDetail(<span class="string">&quot;code&quot;</span>,<span class="number">100</span>)</span><br><span class="line"> .withDetails(map);</span><br><span class="line"></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>myCom &#x3D; MyComHealthIndicator - HealthIndicator 所以类的名字一定要以HealthIndicator为后缀</p>
<p><img src="/pictures/image-20230828150633322.png" alt="image-20230828150633322"></p>
<h5 id="1-6-2-定制-info-endpoint"><a href="#1-6-2-定制-info-endpoint" class="headerlink" title="1.6.2 定制 info endpoint"></a>1.6.2 定制 info endpoint</h5><p>方式一: 编写配置文件</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">info:</span></span><br><span class="line"> <span class="attr">appName:</span> <span class="string">boot-admin</span> <span class="comment">#应用名</span></span><br><span class="line"> <span class="attr">version:</span> <span class="number">2.0</span><span class="number">.1</span> <span class="comment">#版本</span></span><br><span class="line"> <span class="attr">mavenProjectName:</span> <span class="string">@project.artifactId@</span> <span class="comment">#使用@@可以获取maven的pom文件值</span></span><br><span class="line"> <span class="attr">mavenProjectVersion:</span> <span class="string">@project.version@</span></span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230828151416487.png" alt="image-20230828151416487"></p>
<p>方式二: 编写InfoContributor</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.acutuator.info;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.info.Info;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.info.InfoContributor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Collections;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppInfoInfoContributor</span> <span class="keyword">implements</span> <span class="title class_">InfoContributor</span> &#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">contribute</span><span class="params">(Info.Builder builder)</span> &#123;</span><br><span class="line"></span><br><span class="line"> builder.withDetail(<span class="string">&quot;msg&quot;</span>,<span class="string">&quot;你好&quot;</span>)</span><br><span class="line"> .withDetail(<span class="string">&quot;hello&quot;</span>,<span class="string">&quot;atguigu&quot;</span>)</span><br><span class="line"> .withDetails(Collections.singletonMap(<span class="string">&quot;world&quot;</span>,<span class="string">&quot;666600&quot;</span>));</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果我们没有删除上面配置文件的配置,这时我们访问 <a target="_blank" rel="noopener" href="http://localhost:8080/actuator/info">http://localhost:8080/actuator/info</a> 的时候会将配置文件和InfoContributor中的信息共同返回</p>
<p><img src="/pictures/image-20230828152006549.png" alt="image-20230828152006549"></p>
<h5 id="1-6-3-定制Metrics信息"><a href="#1-6-3-定制Metrics信息" class="headerlink" title="1.6.3 定制Metrics信息"></a>1.6.3 定制Metrics信息</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyService</span>&#123;</span><br><span class="line"> </span><br><span class="line"> Counter counter;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//构造器注入MeterRegistry</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">MyService</span><span class="params">(MeterRegistry meterRegistry)</span>&#123;</span><br><span class="line"> <span class="comment">//访问 http://localhost:8080/actuator/metrics 的时候会多一个监控项myservice.method.running.counter</span></span><br><span class="line"> counter = meterRegistry.counter(<span class="string">&quot;myservice.method.running.counter&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">hello</span><span class="params">()</span> &#123;</span><br><span class="line"> <span class="comment">//调用hello方法的时候counter加1</span></span><br><span class="line"> counter.increment();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//也可以使用下面的方式</span></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line">MeterBinder <span class="title function_">queueSize</span><span class="params">(Queue queue)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> (registry) -&gt; Gauge.builder(<span class="string">&quot;queueSize&quot;</span>, queue::size).register(registry);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="1-7-新增Endpoint"><a href="#1-7-新增Endpoint" class="headerlink" title="1.7 新增Endpoint"></a>1.7 新增Endpoint</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.atguigu.boot.acutuator.endpoint;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.endpoint.annotation.Endpoint;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.endpoint.annotation.ReadOperation;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.endpoint.annotation.WriteOperation;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Collections;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Endpoint(id = &quot;myservice&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyServiceEndPoint</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@ReadOperation</span></span><br><span class="line"> <span class="keyword">public</span> Map <span class="title function_">getDockerInfo</span><span class="params">()</span>&#123;</span><br><span class="line"> <span class="comment">//端点的读操作 http://localhost:8080/actuator/myservice</span></span><br><span class="line"> <span class="keyword">return</span> Collections.singletonMap(<span class="string">&quot;dockerInfo&quot;</span>,<span class="string">&quot;docker started.....&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@WriteOperation</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">stopDocker</span><span class="params">()</span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;docker stopped.....&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="/pictures/image-20230828153914619.png" alt="image-20230828153914619"></p>
<p><img src="/pictures/image-20230828153902598.png" alt="image-20230828153902598"></p>
<h4 id="1-8-可视化"><a href="#1-8-可视化" class="headerlink" title="1.8 可视化"></a>1.8 可视化</h4><p>github地址: <a target="_blank" rel="noopener" href="https://github.com/codecentric/spring-boot-admin">https://github.com/codecentric/spring-boot-admin</a></p>
<p>项目文档: <a target="_blank" rel="noopener" href="https://docs.spring-boot-admin.com/current/getting-started.html">https://docs.spring-boot-admin.com/current/getting-started.html</a></p>
<p>1.创建一个新的springBoot项目用作服务端场景只需要选择web场景即可</p>
<p><img src="/pictures/image-20230828154818630.png" alt="image-20230828154818630"></p>
<p>2.引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>de.codecentric<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-admin-starter-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>3.在启动类上添加注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableAdminServer</span></span><br></pre></td></tr></table></figure>
<p>4.修改以下端口号以防和业务的端口冲突</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server.port</span>=<span class="string">8888</span></span><br></pre></td></tr></table></figure>
<p>5.访问<a target="_blank" rel="noopener" href="http://localhost:8888/">http://localhost:8888</a></p>
<p><img src="/pictures/image-20230828155537932.png" alt="image-20230828155537932"></p>
<p>6.客户端上引入依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>de.codecentric<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-admin-starter-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>7.客户端的配置文件添加以下的配置</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.boot.admin.client.url</span>=<span class="string">http://localhost:8888 #服务端的地址</span></span><br><span class="line"><span class="attr">management.endpoints.web.exposure.include</span>=<span class="string">*</span></span><br></pre></td></tr></table></figure>
<p>8.重启一下客户端然后访问服务端的localhost:8080</p>
<p><img src="/pictures/image-20230828160606081.png" alt="image-20230828160606081"></p>
<p>点击应用墙,点击需要查看信息的应用就可以看到应用的详细信息</p>
<p><img src="/pictures/image-20230828160731314.png" alt="image-20230828160731314"></p>
<h2 id="六-原理解析"><a href="#六-原理解析" class="headerlink" title="六.原理解析"></a>六.原理解析</h2><h3 id="1-Profile功能"><a href="#1-Profile功能" class="headerlink" title="1.Profile功能"></a>1.Profile功能</h3><p>为了方便多环境适配springboot简化了profile功能</p>
<ul>
<li><p>默认配置文件 application.yaml任何时候都会加载</p>
</li>
<li><p>指定环境配置文件 application-{env}.yaml</p>
</li>
<li><p>激活指定环境</p>
</li>
<li><ul>
<li>配置文件激活,在默认配置文件 application.yaml 中添加spring.profiles.active&#x3D;xxxx</li>
<li>命令行激活java -jar xxx.jar spring.profiles.active&#x3D;prod</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>修改配置文件的任意值,命令行优先</li>
</ul>
</li>
</ul>
</li>
<li><p>默认配置与环境配置同时生效</p>
</li>
<li><p>同名配置项profile配置优先</p>
</li>
</ul>
<p><strong>@Profile注解</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//@Profile(&quot;prod&quot;)</span></span><br><span class="line"><span class="comment">//可以标注在类和方法上</span></span><br><span class="line"><span class="comment">//标注在类和方法上表示在prod环境下启用</span></span><br></pre></td></tr></table></figure>
<p><strong>外部配置源</strong></p>
<p>常用Java属性文件、YAML文件、环境变量、命令行参数</p>
<p><strong>配置文件查找位置</strong></p>
<p>下面的优先级覆盖上面的优先级</p>
<p>(1) classpath 根路径</p>
<p>(2) classpath 根路径下config目录</p>
<p>(3) jar包当前目录</p>
<p>(4) jar包当前目录的config目录</p>
<p>(5) &#x2F;config子目录的直接子目录</p>
<p><strong>配置文件加载顺序:</strong></p>
<ol>
<li> 当前jar包内部的application.properties和application.yml</li>
<li> 当前jar包内部的application-{profile}.properties 和 application-{profile}.yml</li>
<li> 引用的外部jar包的application.properties和application.yml</li>
<li> 引用的外部jar包的application-{profile}.properties 和 application-{profile}.yml</li>
</ol>
<p><strong>总结:</strong> 指定环境优先,外部优先,后面的可以覆盖前面的同名配置项</p>
</article><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/SpringBoot/">SpringBoot</a></div><div class="post_share"><div class="social-share" data-image="/img/10.png" data-sites="wechat,weibo,qq"></div><link rel="stylesheet" href="/cdn/css/share.min.css" media="print" onload="this.media='all'"><script src="/cdn/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/wechat.jpg" target="_blank"><img class="post-qr-code-img" src="/img/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="/img/alipay.jpg" target="_blank"><img class="post-qr-code-img" src="/img/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><br/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="far fa-comment-alt fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="gitalk-container"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/loading.gif'" alt="avatar"/></div><div class="author-info__name">Jason</div><div class="author-info__description">Debug the World</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">60</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">39</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">10</div></a></div><a id="card-info-btn"><i class="fab fa-microsoft"></i><span>Ctrl + D 收藏</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/JasonsGong" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="tencent://AddContact/?fromId=45&amp;fromSubId=1&amp;subcmd=all&amp;uin=2602183349&amp;website=www.oicqzone.com" target="_blank" title="QQ"><i class="fab fa-qq"></i></a><a class="social-icon" href="mailto:2602183349@qq.com" target="_blank" title="Email"><i class="fas fa-envelope-open-text"></i></a><a class="social-icon" href="https://github.com/JasonsGong?tab=repositories" target="_blank" title="代码仓库"><i class="fas fa-database"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本网站是静态网站,更新页面资源请使用Ctrl+F5;若网站内文章对你有帮助,请使用Ctrl+D收藏该网站</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%80-SpringBoot2%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF-%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8"><span class="toc-text">一.SpringBoot2核心技术-基础入门</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-Spring%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88"><span class="toc-text">1.Spring能做什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-SpringBoot"><span class="toc-text">2.SpringBoot</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-SpringBoot%E7%9A%84%E4%BC%98%E7%82%B9"><span class="toc-text">2.1 SpringBoot的优点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2%E3%80%81SpringBoot%E7%BC%BA%E7%82%B9"><span class="toc-text">2.2、SpringBoot缺点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3"><span class="toc-text">2.3 官方文档</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-SpringBoot%E5%85%A5%E9%97%A8"><span class="toc-text">3.SpringBoot入门</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%A6%81%E6%B1%82"><span class="toc-text">1.系统的要求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-HelloWorld"><span class="toc-text">2.HelloWorld</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E7%AE%80%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-text">3.简化配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-%E7%AE%80%E5%8C%96%E9%83%A8%E7%BD%B2"><span class="toc-text">4.简化部署</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E4%BA%86%E8%A7%A3%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D%E5%8E%9F%E7%90%86"><span class="toc-text">4.了解自动装配原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86"><span class="toc-text">4.1 依赖管理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-SpringBoot%E7%9A%84%E8%87%AA%E5%8A%A8%E7%89%88%E6%9C%AC%E4%BB%B2%E8%A3%81%E6%9C%BA%E5%88%B6"><span class="toc-text">1.SpringBoot的自动版本仲裁机制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-Starters%E5%9C%BA%E6%99%AF%E5%90%AF%E5%8A%A8%E5%99%A8"><span class="toc-text">2.Starters场景启动器</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-text">4.2 自动配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-%E5%AE%B9%E5%99%A8%E5%8A%9F%E8%83%BD"><span class="toc-text">4.3 容器功能</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E7%BB%84%E4%BB%B6%E6%B7%BB%E5%8A%A0"><span class="toc-text">1.组件添加</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-1-Configuration"><span class="toc-text">1.1 @Configuration</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-2-Bean-Component-Controller-Service-Repository"><span class="toc-text">1.2 @Bean @Component @Controller @Service @Repository</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-3-ComponentScan-Import"><span class="toc-text">1.3 @ComponentScan @Import</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-4-Conditional-%E6%9D%A1%E4%BB%B6%E8%A3%85%E9%85%8D%EF%BC%9A%E6%BB%A1%E8%B6%B3Conditional%E6%8C%87%E5%AE%9A%E7%9A%84%E6%9D%A1%E4%BB%B6%EF%BC%8C%E5%88%99%E8%BF%9B%E8%A1%8C%E7%BB%84%E4%BB%B6%E6%B3%A8%E5%85%A5"><span class="toc-text">1.4 @Conditional 条件装配满足Conditional指定的条件则进行组件注入</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E5%8E%9F%E7%94%9F%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%BC%95%E5%85%A5"><span class="toc-text">2.原生配置文件的引入</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#2-1%E3%80%81-ImportResource"><span class="toc-text">2.1、@ImportResource</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-%E9%85%8D%E7%BD%AE%E7%BB%91%E5%AE%9A"><span class="toc-text">3.配置绑定</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#3-1-ConfigurationProperties"><span class="toc-text">3.1 @ConfigurationProperties</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E5%85%A5%E9%97%A8"><span class="toc-text">4.4 自动配置原理入门</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E5%BC%95%E5%AF%BC%E5%8A%A0%E8%BD%BD%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB"><span class="toc-text">1.引导加载自动配置类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E6%8C%89%E9%9C%80%E5%BC%80%E5%90%AF%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9"><span class="toc-text">2.按需开启自动配置项</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-%E4%BF%AE%E6%94%B9%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE"><span class="toc-text">3.修改默认配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5"><span class="toc-text">3.4.最佳实践</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-5-%E7%AE%80%E5%8C%96%E5%BC%80%E5%8F%91"><span class="toc-text">4.5 简化开发</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-Lombok"><span class="toc-text">1.Lombok</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E7%AE%80%E5%8C%96%E6%97%A5%E5%BF%97%E5%BC%80%E5%8F%91"><span class="toc-text">2.简化日志开发</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-dev-tools"><span class="toc-text">3.dev-tools</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-Spring-Initailizr%EF%BC%88%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%91%E5%AF%BC%EF%BC%89"><span class="toc-text">4.Spring Initailizr项目初始化向导</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-text"></span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8C-SpringBoot2%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF-%E6%A0%B8%E5%BF%83%E5%8A%9F%E8%83%BD"><span class="toc-text">二.SpringBoot2核心技术-核心功能</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">一.配置文件</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B"><span class="toc-text">1、文件类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1%E3%80%81properties"><span class="toc-text">1.1、properties</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2%E3%80%81yaml"><span class="toc-text">1.2、yaml</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-2-1%E3%80%81%E7%AE%80%E4%BB%8B"><span class="toc-text">1.2.1、简介</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-2-2%E3%80%81%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95"><span class="toc-text">1.2.2、基本语法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-2-3%E3%80%81%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.2.3、数据类型</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-2-4%E3%80%81%E7%A4%BA%E4%BE%8B"><span class="toc-text">1.2.4、示例</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E9%85%8D%E7%BD%AE%E6%8F%90%E7%A4%BA"><span class="toc-text">2、配置提示</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8C-Web%E5%BC%80%E5%8F%91"><span class="toc-text">二.Web开发</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E7%AE%80%E5%8D%95%E7%9A%84%E5%8A%9F%E8%83%BD%E5%88%86%E6%9E%90"><span class="toc-text">1.简单的功能分析</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E8%AE%BF%E9%97%AE"><span class="toc-text">1.1 静态资源访问</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%9B%AE%E5%BD%95"><span class="toc-text">1.静态资源目录</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E8%AE%BF%E9%97%AE%E5%89%8D%E7%BC%80"><span class="toc-text">2.静态资源访问前缀</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-webjar"><span class="toc-text">3.webjar</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-%E6%AC%A2%E8%BF%8E%E9%A1%B5%E6%94%AF%E6%8C%81"><span class="toc-text">1.2 欢迎页支持</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-%E8%87%AA%E5%AE%9A%E4%B9%89-Favicon"><span class="toc-text">1.3 自定义 Favicon</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="toc-text">1.4 静态资源配置原理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E5%A4%84%E7%90%86%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94"><span class="toc-text">2.请求参数处理与数据响应</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1%E3%80%81%E8%AF%B7%E6%B1%82%E6%98%A0%E5%B0%84"><span class="toc-text">2.1、请求映射</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1%E3%80%81rest%E4%BD%BF%E7%94%A8%E4%B8%8E%E5%8E%9F%E7%90%86"><span class="toc-text">1、rest使用与原理</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2%E3%80%81%E8%AF%B7%E6%B1%82%E6%98%A0%E5%B0%84%E5%8E%9F%E7%90%86"><span class="toc-text">2、请求映射原理</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2%E3%80%81%E6%99%AE%E9%80%9A%E5%8F%82%E6%95%B0%E4%B8%8E%E5%9F%BA%E6%9C%AC%E6%B3%A8%E8%A7%A3"><span class="toc-text">2.2、普通参数与基本注解</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%B3%A8%E8%A7%A3"><span class="toc-text">1.注解</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-Servlet-API"><span class="toc-text">2.Servlet API</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%A4%8D%E6%9D%82%E5%8F%82%E6%95%B0%EF%BC%9A"><span class="toc-text">3.复杂参数:</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1%E5%8F%82%E6%95%B0"><span class="toc-text">4.自定义对象参数</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-%E5%8F%82%E6%95%B0%E5%A4%84%E7%90%86%E5%8E%9F%E7%90%86"><span class="toc-text">2.3 参数处理原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E4%B8%8E%E5%86%85%E5%AE%B9%E5%8D%8F%E5%95%86"><span class="toc-text">2.4 数据响应与内容协商</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#2-4-1-%E7%9B%B8%E5%85%B3%E4%BE%9D%E8%B5%96%E7%9A%84%E5%BC%95%E5%85%A5"><span class="toc-text">2.4.1 相关依赖的引入</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-4-2-%E5%86%85%E5%AE%B9%E5%8D%8F%E5%95%86%E5%8E%9F%E7%90%86"><span class="toc-text">2.4.2 内容协商原理</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-4-3-%E8%87%AA%E5%AE%9A%E4%B9%89MessageConverter"><span class="toc-text">2.4.3 自定义MessageConverter</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E8%A7%86%E5%9B%BE%E8%A7%A3%E6%9E%90%E4%B8%8E%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E"><span class="toc-text">3.视图解析与模板引擎</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-%E8%A7%86%E5%9B%BE%E8%A7%A3%E6%9E%90"><span class="toc-text">3.1 视图解析</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E-Thymeleaf"><span class="toc-text">3.2 模板引擎-Thymeleaf</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#3-2-1-Thymeleaf%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">3.2.1 Thymeleaf的使用</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E6%B3%A8%E6%84%8F%E7%82%B9"><span class="toc-text">3.3 后台管理系统注意点</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="toc-text">4.拦截器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-HandlerInterceptor%E6%8E%A5%E5%8F%A3"><span class="toc-text">1.HandlerInterceptor接口</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E6%8B%A6%E6%88%AA%E5%99%A8%E5%AE%9E%E7%8E%B0%E7%99%BB%E5%BD%95%E6%A3%80%E6%9F%A5%E6%93%8D%E4%BD%9C"><span class="toc-text">2.拦截器实现登录检查操作</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8E%9F%E7%90%86"><span class="toc-text">3.拦截器原理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0"><span class="toc-text">5.文件上传</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E9%A1%B5%E9%9D%A2%E8%A1%A8%E5%8D%95"><span class="toc-text">1.页面表单</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E4%BB%A3%E7%A0%81"><span class="toc-text">2.文件上传代码</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-MultipartAutoConfiguration"><span class="toc-text">3.MultipartAutoConfiguration</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86"><span class="toc-text">6.异常处理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E9%BB%98%E8%AE%A4%E8%A7%84%E5%88%99"><span class="toc-text">1.默认规则</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%94%99%E8%AF%AF%E9%A1%B5%E9%9D%A2"><span class="toc-text">2.自定义错误页面</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-Web%E5%8E%9F%E7%94%9F%E7%BB%84%E4%BB%B6%E6%B3%A8%E5%85%A5%EF%BC%88Servlet%E3%80%81Filter%E3%80%81Listener%EF%BC%89"><span class="toc-text">7.Web原生组件注入Servlet、Filter、Listener</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-%E4%BD%BF%E7%94%A8Servlet-Api"><span class="toc-text">7.1 使用Servlet Api</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%8E%9F%E7%94%9F%E7%9A%84Servlet%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">1.原生的Servlet的使用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%8E%9F%E7%94%9F%E7%9A%84Filter%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">2.原生的Filter的使用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%8E%9F%E7%94%9F%E7%9A%84Listener%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">3.原生的Listener的使用</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-%E4%BD%BF%E7%94%A8RegistrationBean"><span class="toc-text">7.2 使用RegistrationBean</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-%E5%B5%8C%E5%85%A5%E5%BC%8FServlet%E5%AE%B9%E5%99%A8"><span class="toc-text">8.嵌入式Servlet容器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-%E5%88%87%E6%8D%A2%E5%B5%8C%E5%85%A5%E5%BC%8FServlet%E5%AE%B9%E5%99%A8"><span class="toc-text">8.1 切换嵌入式Servlet容器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-%E5%AE%9A%E5%88%B6Servlet%E5%AE%B9%E5%99%A8"><span class="toc-text">8.2 定制Servlet容器</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89-%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE"><span class="toc-text">三.数据访问</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-SQL"><span class="toc-text">1.SQL</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-JDBC%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">1.1 JDBC的使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-%E5%88%86%E6%9E%90%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-text">1.2 分析自动配置</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9B%9B-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95"><span class="toc-text">四.单元测试</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-JUnit5%E7%9A%84%E5%8F%98%E5%8C%96"><span class="toc-text">1.JUnit5的变化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-JUnit5%E5%B8%B8%E7%94%A8%E6%B3%A8%E8%A7%A3"><span class="toc-text">2.JUnit5常用注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E6%96%AD%E8%A8%80"><span class="toc-text">3.断言</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-%E7%AE%80%E5%8D%95%E6%96%AD%E8%A8%80"><span class="toc-text">3.1 简单断言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-%E6%95%B0%E7%BB%84%E6%96%AD%E8%A8%80"><span class="toc-text">3.2 数组断言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-%E7%BB%84%E5%90%88%E6%96%AD%E8%A8%80"><span class="toc-text">3.3 组合断言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-%E5%BC%82%E5%B8%B8%E6%96%AD%E8%A8%80"><span class="toc-text">3.4 异常断言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-%E8%B6%85%E6%97%B6%E6%96%AD%E8%A8%80"><span class="toc-text">3.5 超时断言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-6-%E5%BF%AB%E9%80%9F%E5%A4%B1%E8%B4%A5"><span class="toc-text">3.6 快速失败</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-%E5%89%8D%E7%BD%AE%E6%9D%A1%E4%BB%B6"><span class="toc-text">4.前置条件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-%E5%B5%8C%E5%A5%97%E6%B5%8B%E8%AF%95"><span class="toc-text">5.嵌套测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-%E5%8F%82%E6%95%B0%E5%8C%96%E6%B5%8B%E8%AF%95"><span class="toc-text">6.参数化测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-%E8%BF%81%E7%A7%BB%E6%8C%87%E5%8D%97"><span class="toc-text">7.迁移指南</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%94-%E6%8C%87%E6%A0%87%E7%9B%91%E6%8E%A7"><span class="toc-text">五.指标监控</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-SpringBoot-Actuator"><span class="toc-text">1.SpringBoot Actuator</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8"><span class="toc-text">1.1 如何使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-%E5%B8%B8%E7%94%A8%E7%9A%84EndPoints"><span class="toc-text">1.2 常用的EndPoints</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-Health-Endpoint"><span class="toc-text">1.3 Health Endpoint</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-Metrics-Endpoint"><span class="toc-text">1.4 Metrics Endpoint</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-%E7%AE%A1%E7%90%86Endpoint"><span class="toc-text">1.5 管理Endpoint</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-6-%E5%AE%9A%E5%88%B6Endpoint"><span class="toc-text">1.6 定制Endpoint</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-6-1-%E5%AE%9A%E5%88%B6health-endpoint"><span class="toc-text">1.6.1 定制health endpoint</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-6-2-%E5%AE%9A%E5%88%B6-info-endpoint"><span class="toc-text">1.6.2 定制 info endpoint</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#1-6-3-%E5%AE%9A%E5%88%B6Metrics%E4%BF%A1%E6%81%AF"><span class="toc-text">1.6.3 定制Metrics信息</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-7-%E6%96%B0%E5%A2%9EEndpoint"><span class="toc-text">1.7 新增Endpoint</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-8-%E5%8F%AF%E8%A7%86%E5%8C%96"><span class="toc-text">1.8 可视化</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%AD-%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90"><span class="toc-text">六.原理解析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-Profile%E5%8A%9F%E8%83%BD"><span class="toc-text">1.Profile功能</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最近更新</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/8957.html" title="Linux从入门到进阶"><img src="/img/8.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Linux从入门到进阶"/></a><div class="content"><a class="title" href="/posts/8957.html" title="Linux从入门到进阶">Linux从入门到进阶</a><time datetime="2024-05-10T05:31:11.691Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/35630.html" title="接口测试工具"><img src="/img/2.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="接口测试工具"/></a><div class="content"><a class="title" href="/posts/35630.html" title="接口测试工具">接口测试工具</a><time datetime="2024-05-10T05:31:11.686Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/32246.html" title="SpringBoot中整合Swagger2"><img src="/img/3.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="SpringBoot中整合Swagger2"/></a><div class="content"><a class="title" href="/posts/32246.html" title="SpringBoot中整合Swagger2">SpringBoot中整合Swagger2</a><time datetime="2024-05-10T05:31:11.681Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/19306.html" title="Docker容器化技术"><img src="/img/1.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Docker容器化技术"/></a><div class="content"><a class="title" href="/posts/19306.html" title="Docker容器化技术">Docker容器化技术</a><time datetime="2024-05-10T05:31:11.675Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/20683.html" title="Linux中开发环境的搭建"><img src="/img/8.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Linux中开发环境的搭建"/></a><div class="content"><a class="title" href="/posts/20683.html" title="Linux中开发环境的搭建">Linux中开发环境的搭建</a><time datetime="2024-05-10T05:31:11.669Z" title="更新于 2024-05-10 13:31:11">2024-05-10</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comment-alt"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/cdn/js/medium-zoom.min.js"></script><script src="/cdn/js/instantpage.min.js" type="module"></script><script src="/cdn/js/snackbar.min.js"></script><div class="js-pjax"><script>function loadGitalk () {
function initGitalk () {
var gitalk = new Gitalk(Object.assign({
clientID: '00fb27b1e484536359c2',
clientSecret: 'be41a12281c68b6e228d1a27e8d08aeb91541145',
repo: 'BlogComment',
owner: 'JasonsGong',
admin: ['JasonsGong'],
id: '4e6ca67ac0f4ff444c69bcec9fb8ad8b',
updateCountCallback: commentCount
},null))
gitalk.render('gitalk-container')
}
if (typeof Gitalk === 'function') initGitalk()
else {
getCSS('/cdn/css/gitalk.min.css')
getScript('/cdn/js/gitalk.min.js').then(initGitalk)
}
}
function commentCount(n){
let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
if (isCommentCount) {
isCommentCount.textContent= n
}
}
if ('Gitalk' === 'Gitalk' || !true) {
if (true) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk)
else loadGitalk()
} else {
function loadOtherComment () {
loadGitalk()
}
}</script></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span> 数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><br/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div><!-- hexo injector body_end start --><script data-pjax>
function butterfly_swiper_injector_config(){
var parent_div_git = document.getElementById('recent-posts');
var item_html = '<div class="recent-post-item" style="height: auto;width: 100%"><div class="blog-slider swiper-container-fade swiper-container-horizontal" id="swiper_container"><div class="blog-slider__wrp swiper-wrapper" style="transition-duration: 0ms;"><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/19306.html" alt=""><img width="48" height="48" src="/img/1.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-04-21</span><a class="blog-slider__title" href="posts/19306.html" alt="">Docker容器化技术</a><div class="blog-slider__text">Docker</div><a class="blog-slider__button" href="posts/19306.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/47003.html" alt=""><img width="48" height="48" src="/img/5.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-03-10</span><a class="blog-slider__title" href="posts/47003.html" alt="">常用正则表达式大全</a><div class="blog-slider__text">正则表达式</div><a class="blog-slider__button" href="posts/47003.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/20683.html" alt=""><img width="48" height="48" src="/img/8.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-05</span><a class="blog-slider__title" href="posts/20683.html" alt="">Linux中开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/20683.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/63333.html" alt=""><img width="48" height="48" src="/img/10.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-03</span><a class="blog-slider__title" href="posts/63333.html" alt="">开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/63333.html" alt="">详情 </a></div></div></div><div class="blog-slider__pagination swiper-pagination-clickable swiper-pagination-bullets"></div></div></div>';
if (parent_div_git !== null && typeof parent_div_git !== 'undefined') {
parent_div_git.insertAdjacentHTML("afterbegin",item_html)
}
}
var elist = 'undefined'.split(',');
var cpage = location.pathname;
var epage = 'all';
var flag = 0;
for (var i=0;i<elist.length;i++){
if (cpage.includes(elist[i])){
flag++;
}
}
if ((epage ==='all')&&(flag == 0)){
butterfly_swiper_injector_config();
}
else if (epage === cpage){
butterfly_swiper_injector_config();
}
</script><script defer src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js"></script><script defer data-pjax src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js"></script><!-- hexo injector body_end end --></body></html>