日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

SpringBoot笔记

發(fā)布時(shí)間:2023/12/9 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot笔记 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

      • 1?? 簡(jiǎn)介
        • 一. 什么是 IoC 容器?
        • 二. AOP面向切面編程
        • 三. SSM整合
        • 四. HttpServletRequest
        • 五. HttpServletResponse
        • 六. Cookie 與 Session
        • 七. Cookie
        • 八. Session
        • 九. 轉(zhuǎn)發(fā)與重定向
        • 十. Spring項(xiàng)目轉(zhuǎn)SpringBoot
        • 十一. Spring生命周期
        • 十二. 什么是 pom
        • 十三. 為什么會(huì)返回JSON格式數(shù)據(jù)
        • 十四. 跨域請(qǐng)求 CORS
      • 2?? Spring基礎(chǔ)知識(shí)
        • 一. 注解開(kāi)發(fā)說(shuō)明
        • 二. 配置 Bean
        • 三. 配置第三方 Bean
        • 四. 單例與多實(shí)例
        • 五. @Autowired說(shuō)明
        • 六. Bean的生命周期
        • 七. 條件裝配:Bean加載控制
        • 八. 為Bean內(nèi)的變量賦值
        • 九. Spring事務(wù)管理
        • 十. JdbcTemplate解釋
        • 十一. P命名空間
        • 十二. 關(guān)閉ApplicationContext
        • 十三. 完全注解開(kāi)發(fā)
        • 十四. 獲取 Bean
        • 十五. 導(dǎo)入其他配置項(xiàng)
        • 十六. Bean的分類
      • 3?? Spring MVC基礎(chǔ)知識(shí)
        • 一. MVC簡(jiǎn)介
        • 二. 衍生的 Bean注解
        • 三. 路徑疊加
        • 四. RESTful風(fēng)格
        • 五. @RequestMapping詳解
        • 六. 路徑 ant風(fēng)格
        • 七. 非 RESTful風(fēng)格說(shuō)明
        • 八. 域共享對(duì)象
        • 九. ModelAndView
        • 十. 請(qǐng)求響應(yīng)擴(kuò)展
        • 十一. MVC工作流程
        • 十二. 文件下載
        • 十三. 文件上傳
        • 十四. 攔截、過(guò)濾、分發(fā)器總結(jié)
        • 十五. @RequestParam、@PathVariable區(qū)別
        • 十六. 視圖解析器
        • 十七. SpringMVC執(zhí)行流程
        • 十八. Thymeleaf說(shuō)明
      • 4?? SpringBoot小知識(shí)點(diǎn)
      • 5?? SpringBoot基礎(chǔ)知識(shí)
        • 一. 初始項(xiàng)目結(jié)構(gòu)
        • 二. delete、put請(qǐng)求說(shuō)明
        • 三. jar包與 war包的區(qū)別
        • 四. start 與 parent的區(qū)別
        • 五. @SpringBootApplication說(shuō)明
        • 六. #{ }與 ${ }說(shuō)明
        • 七. @ControllerAdvice說(shuō)明
        • 八. 臨時(shí)配置說(shuō)明
        • 九. yml格式說(shuō)明
        • 十. 松散綁定說(shuō)明
      • 6?? SpringBoot常用操作
        • 一. 頁(yè)面跳轉(zhuǎn)
        • 二. 注解方式獲取請(qǐng)求頭
        • 三. 注解方式獲取Cookie
        • 四. 編碼格式修改
        • 五. 發(fā)送郵件
        • 六. Scheduled定時(shí)任務(wù)
        • 七. Cron格式編寫(xiě)指南
        • 八. SpringBootAdmin監(jiān)控
        • 九. 消息中間件
        • 十. 自定義錯(cuò)誤頁(yè)
        • 十一. Slf4j日志使用
        • 十二. 靜態(tài)資源訪問(wèn)
        • 十三. 路徑映射
        • 十四. 服務(wù)器日志
        • 十五. 多環(huán)境開(kāi)發(fā) Profile
        • 十六. 優(yōu)先執(zhí)行的代碼
        • 十七. 異常處理器
        • 十八. 配置日志等級(jí)
        • 十九. 兼容xml配置文件
        • 二十. 讀取標(biāo)準(zhǔn) yml配置
        • 二十一. 讀取第三方 yml配置
        • 二十二. 攔截器
        • 二十三. 頁(yè)面跳轉(zhuǎn)
      • 7?? SpringBoot常用技巧
        • 一. 獲取UUID的正確姿勢(shì)
        • 二. 全路徑名
        • 三. 頁(yè)面重定向
        • 四. 表格的畫(huà)法
        • 五. yml中相互引用
        • 六. 隨時(shí)獲取 ApplicationContext
        • 七. 網(wǎng)站圖標(biāo) favicon
        • 八. 跳過(guò)測(cè)試模塊
        • 九. 排除自動(dòng)配置
        • 十. 查看 pom組件版本
        • 十一. 正確的項(xiàng)目創(chuàng)建流程
        • 十二. 離線創(chuàng)建SpringBoot程序
        • 十三. 快速制作程序模板
        • 十四. Tomcat替換成Jetty
        • 十五. 修改Banner
        • 十六. 測(cè)試中開(kāi)啟服務(wù)器配置
        • 十七. 測(cè)試中開(kāi)啟事務(wù)
        • 十八. 測(cè)試中的臨時(shí)屬性
        • 十九. @JsonIgnore
        • 二十. 項(xiàng)目打包構(gòu)建
        • 二十一. IDEA隱藏文件
        • 二十二. jdk8單位類
      • 8?? SpringBoot不常用操作
        • 1. 修改配置文件名
        • 2. maven控制yml環(huán)境
        • 3. JDBC使用
        • 4. 熱部署
        • 5. 開(kāi)啟 Bean校驗(yàn)
        • 6. 代碼中編寫(xiě)測(cè)試
        • 7. 測(cè)試用例中設(shè)置隨機(jī)數(shù)據(jù)
      • 9?? 整合第三方
        • 一. 整合Mybatis
        • 二. 整合MybatisPlus
        • 三. 整合Druid
      • 🔟 Spring Security
        • 一. 簡(jiǎn)介
        • 二. 使用步驟
        • 三. 自定義登錄頁(yè)面與返回值
        • 四. 注銷登錄
        • 五. 加鹽 Salt
        • 六. 使用注解進(jìn)行配置
        • 七. 持久層存儲(chǔ):數(shù)據(jù)庫(kù)
        • 八. 令牌技術(shù):token
        • 九. WebSocket
        • 十. Swagger2


1?? 簡(jiǎn)介

一. 什么是 IoC 容器?

  • 簡(jiǎn)介

    Inversion of Control 控制反轉(zhuǎn),

    又稱為依賴注入 DI ——Dependency Injection。

  • 解決痛點(diǎn)

    大型程序之間的高耦合性與冗余性,共享組件、統(tǒng)一銷毀。

  • 底層原理

    XML解析、工廠模式、反射。

    IOC容器底層就是對(duì)象工廠

  • 意義

    ? 傳統(tǒng)的應(yīng)用程序中,控制權(quán)在程序本身,程序的控制流程完全由開(kāi)發(fā)者控制。在IoC模式下,控制權(quán)發(fā)生了反轉(zhuǎn),即從應(yīng)用程序轉(zhuǎn)移到了IoC容器,所有組件不再由應(yīng)用程序自己創(chuàng)建和配置,而是由IoC容器負(fù)責(zé),這樣,應(yīng)用程序只需要直接使用已經(jīng)創(chuàng)建好并且配置好的組件。為了能讓組件在IoC容器中被“裝配”出來(lái),需要某種“注入”機(jī)制,其將組件的創(chuàng)建+配置與組件的使用相分離,并且,由IoC容器負(fù)責(zé)管理組件的生命周期。

    總結(jié):Ioc意味著將你設(shè)計(jì)好的對(duì)象交給容器控制,而不是按照傳統(tǒng)在對(duì)象內(nèi)部直接控制

  • 小點(diǎn):

    • 在 Spring IoC程序中,我們把所有的組件統(tǒng)稱為 Java Bean。
    • Spring容器是通過(guò)讀取XML文件后使用反射完成的,其實(shí)所有的配置文件差不多都是這樣,Java的反射機(jī)制。
    • Spring容器就是 ApplicationContext,它是一個(gè)接口,有很多實(shí)現(xiàn)類,這里我們選擇 ClassPathXmlApplicationContext,表示它會(huì)自動(dòng)從classpath中查找指定的XML配置文件。
    • Spring還提供了另外一種IoC容器:懶加載對(duì)象 BeanFactory。使用方法和 ApplicationContext一樣,但是懶加載主要是第一次獲取時(shí)才會(huì)加載指定的 Bean對(duì)象,而 ApplicationContext則會(huì)在創(chuàng)建時(shí)一次性加載所有的 Bean對(duì)象。
    // 從 ApplicationContext里面獲取 Bean UserMapper mapper=context.gerBean(UserMapper.class);
  • 二. AOP面向切面編程

  • 簡(jiǎn)介:

    ? SpringBoot支持面向切面編程,其可以在不改動(dòng)原代碼的動(dòng)態(tài)添加代碼、動(dòng)態(tài)刪去代碼。這在日志記錄、安全檢查和事務(wù)等方面很有用。AOP技術(shù)本質(zhì)上就是一個(gè)動(dòng)態(tài)代理,讓我們可以把一些常用功能如權(quán)限檢查、日志、事務(wù)從業(yè)務(wù)方法中剝離出來(lái)。

  • 題外話:

    ? Spring的 AOP實(shí)現(xiàn)基于 JVM的動(dòng)態(tài)代理,所以我們有時(shí)候也會(huì)這樣子形容——AOP代理、AOP代理對(duì)象,意即AOP代理了本來(lái)的類對(duì)象。

  • 在 Java平臺(tái)上對(duì)于AOP的織入,一共有三種方式:

    • 編譯器:由編譯器把切面編譯進(jìn)字節(jié)碼,使用aspect關(guān)鍵字。
    • 類加載器:利用一個(gè)特殊的類加載器,在目標(biāo)類被裝載到JVM時(shí),對(duì)目標(biāo)類的字節(jié)碼文件進(jìn)行重新加強(qiáng)。
    • 運(yùn)行期:目標(biāo)對(duì)象和切面都是普通的Java類,通過(guò)JVM的動(dòng)態(tài)代理對(duì)象功能或者第三方庫(kù)實(shí)現(xiàn)運(yùn)行期間動(dòng)態(tài)織入。(最簡(jiǎn)單的方式)
  • 原理解釋:

    ? Spring對(duì)接口類型使用JDK動(dòng)態(tài)代理,對(duì)普通類使用CGLIB創(chuàng)建子類,在之后使用的也是它的子類,但對(duì)于用戶來(lái)說(shuō)是無(wú)感的。如果一個(gè)Bean的class是final,Spring將無(wú)法為其創(chuàng)建子類。

    // 原類為 UserTest,打印出來(lái)可以看到被 Spring enhance // 并非原類,為其子類。 class com.thinkstu.test.UserTest$$EnhancerBySpringCGLIB$$217a2220
  • AOP:Aspect-Orinented Programing 面向切面編程。

  • OOP:Object-Oriented Programming面向?qū)ο缶幊?#xff0c;封裝、繼承、多態(tài)。

  • 常用術(shù)語(yǔ):

  • AOP的使用:

    • 導(dǎo)包
    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>
    • 切入:新定義類,并 @Aspect總開(kāi)關(guān)注解,切入點(diǎn)注解。

      • @Around:環(huán)繞通知是所有通知里功能最為強(qiáng)大的注解,可以實(shí)現(xiàn)前直通知、后直通知、異常通知以及返回通知的功能。

      • @Pointcut解釋:

        @Pointcut("execution(* com.thinkstu.controller.*.*(..))")

    @Aspect //表示AOP @Component public class UsersAspect {@Pointcut("execution(* com.thinkstu.controller.*.*(..))")public void cut() {}@Before(value = "cut()")public void before(JoinPoint joinPoint) { // 返回方法名String name = joinPoint.getSignature().getName();System.out.println("before開(kāi)始執(zhí)行----" + name);}@After(value = "cut()")public void after(JoinPoint joinPoint) {System.out.println("after開(kāi)始執(zhí)行----");}@AfterReturning(value = "cut()", returning = "result")public void getResult(JoinPoint joinPoint, Object result) { // 方法返回值System.out.println("after開(kāi)始執(zhí)行----" + result);}@AfterThrowing(value = "cut()", throwing = "ex")public void afterThrowing(Exception ex) {System.out.println("發(fā)生異常------afterThrowing" + ex);}@Around(value = "cut()")public void around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around優(yōu)先執(zhí)行的語(yǔ)句----------");pjp.proceed();System.out.println("around中方法已執(zhí)行----------");} }
  • 三. SSM整合

    ? SSM整合指 Spring、SpringMVC、Mybatis的整合。

    四. HttpServletRequest

  • 說(shuō)明

    ? 原生接口。當(dāng)客戶端通過(guò)HTTP協(xié)議訪問(wèn)服務(wù)器時(shí),HTTP請(qǐng)求頭中的所有信息都封裝在這個(gè)對(duì)象中。

    通過(guò) HttpServletRequest我們可以獲得很多信息。

  • 部分功能

    • headers:必須獲得全部的 key,而后才能遍歷出所有的 value。

    • getRemoteAddr:返回發(fā)出請(qǐng)求的客戶機(jī)的IP地址。

    • getParameter(“username”):獲取請(qǐng)求參數(shù)

  • 提示:

    獲取全部請(qǐng)求信息應(yīng)該使用 RequestEntity,而不是HttpServletRequest。

    單純簡(jiǎn)單獲取請(qǐng)求體應(yīng)該使用 @RequestHeader注解,而不是HttpServletRequest。

    主要感覺(jué) HttpServletRequest有點(diǎn)難用。

  • 五. HttpServletResponse

    ? 原生方式控制返回,但是一般不這樣。

  • 兩種響應(yīng)方式
  • 六. Cookie 與 Session

  • Cookie與 Session的區(qū)別:Session比Cookie安全

    Cookie是客戶端技術(shù),存儲(chǔ)在客戶端。Session是服務(wù)器端技術(shù),存儲(chǔ)在服務(wù)端。

  • 使用原因

    ? HTTP 是無(wú)狀態(tài)協(xié)議,它不能以狀態(tài)來(lái)區(qū)分和管理請(qǐng)求和響應(yīng),也就是說(shuō)服務(wù)器單從網(wǎng)絡(luò)連接上無(wú)從知道客戶身份。于是我們可以給客戶端頒發(fā)通行證,如此服務(wù)端便能識(shí)別客戶的身份,這就是 Cookie的工作原理。

  • 七. Cookie

  • 概念
  • ? Cookie是服務(wù)器存儲(chǔ)在本地機(jī)器上的一小段文本。是客戶端保存用戶信息的一種機(jī)制,用來(lái)記錄用戶的一些信息,并隨著每次請(qǐng)求發(fā)送到服務(wù)器。

    ? Cookie會(huì)根據(jù)響應(yīng)報(bào)文里的一個(gè)叫做Set-Cookie的首部字段信息,通知客戶端保存Cookie。當(dāng)下次客戶端再向服務(wù)端發(fā)起請(qǐng)求時(shí),客戶端會(huì)自動(dòng)在請(qǐng)求報(bào)文中加入Cookie值之后發(fā)送出去。然后服務(wù)器端會(huì)根據(jù)記錄,得到之前的最后狀態(tài)信息。

  • set-cookie字段解釋
    • logcookie = 3qjj:設(shè)置 Cookie的 key、value值。
    • Expires:設(shè)置 cookie有效期,當(dāng)省略 expires屬性時(shí),Cookie在本次瀏覽器窗口關(guān)閉后失效。如果設(shè)置了過(guò)期時(shí)間,瀏覽器就會(huì)把cookie保存到硬盤(pán)上,關(guān)閉后再次打開(kāi)瀏覽器,這些cookie依然有效直到超過(guò)設(shè)定的過(guò)期時(shí)間。
    • Max-age:如果你創(chuàng)建了一個(gè)cookie,并將他發(fā)送到瀏覽器,默認(rèn)情況下它是一個(gè)會(huì)話級(jí)別的cookie:存儲(chǔ)在瀏覽器的內(nèi)存中,用戶退出瀏覽器之后被刪除。如果 你希望瀏覽器將該cookie存儲(chǔ)在磁盤(pán)上,則需要使用maxAge,并給出一個(gè)以秒為單位的時(shí)間。將最大時(shí)效設(shè)為0則是命令瀏覽器刪除該 cookie。
    • path:限制指定Cookie 的發(fā)送范圍的文件目錄,不過(guò)另有辦法可避開(kāi)這項(xiàng)限制。
    • domain:domain屬性指定一級(jí)域名。比如,指定 domain是 thinkstu.com,那么只有從一級(jí)域名是 thinkstu.com網(wǎng)址發(fā)送過(guò)來(lái)的請(qǐng)求才有效。
    • secure:設(shè)置只有在HTTPS安全連接時(shí),才可以發(fā)送Cookie。
    • HttpOnly:使 JavaScript 腳本無(wú)法獲得 Cookie。通過(guò)上述設(shè)置,通常從 Web 頁(yè)面內(nèi)還可以對(duì)Cookie 進(jìn)行讀取操作,但使用 JavaScript 的 document.cookie無(wú)法讀取附加 HttpOnly 屬性后的Cookie 的內(nèi)容。
  • Max-age與 Expires的區(qū)別

    Expires和max-age都可以用來(lái)指定文檔的過(guò)期時(shí)間,但是二者有一些細(xì)微差別。

    Expires表示絕對(duì)時(shí)間,HTTP 1.0開(kāi)始使用。Max-age表示相對(duì)時(shí)間,HTTP 1.1開(kāi)始使用。

  • 限制情況

    單個(gè)cookie在客戶端的限制是3K,就是說(shuō)一個(gè)站點(diǎn)在客戶端存放的COOKIE不能超過(guò)3K。

  • 八. Session

  • 思想

    ? 當(dāng)用戶第一次訪問(wèn)網(wǎng)站時(shí),網(wǎng)站會(huì)為用戶生成唯一的 Session ID值,而后 Session會(huì)自動(dòng)跟隨響應(yīng)報(bào)文 set-Cookie返回給客戶端,所以可以說(shuō) Session的設(shè)置在一定程度上依賴于 Cookie。可以把Session ID 想象成一種用以區(qū)分不同用戶的唯一Id。

  • 強(qiáng)依賴 Cookie與弱依賴

    ? 當(dāng)我們完全禁掉瀏覽器的cookie的時(shí)候,服務(wù)端的session可能不能正常使用。這取決于當(dāng)前環(huán)境中 Session對(duì) Cookie的依賴程度,通過(guò)規(guī)避寫(xiě)法可以避免強(qiáng)依賴。比如當(dāng)禁用 Cookie時(shí),PHP會(huì)自動(dòng)把Session ID附著在URL中,繼續(xù)正常使用。

  • 九. 轉(zhuǎn)發(fā)與重定向

  • 轉(zhuǎn)發(fā):forward,客戶端只發(fā)送了一次請(qǐng)求,該請(qǐng)求沿著“轉(zhuǎn)發(fā)鏈”執(zhí)行,所以可以通過(guò)request來(lái)共享數(shù)據(jù)。
  • 重定向:redirect,客戶端發(fā)送了兩次請(qǐng)求,相當(dāng)于客戶端自己重新發(fā)送了一次請(qǐng)求,這是兩次不一樣的請(qǐng)求,不能通過(guò)request共享數(shù)據(jù)。
  • 十. Spring項(xiàng)目轉(zhuǎn)SpringBoot

  • 思想:SpringBoot是為了簡(jiǎn)化 Spring項(xiàng)目而生的,其兩者在很大程度上兼容。
  • 大致步驟
    • 直接拷貝業(yè)務(wù)代碼、pom包(這里刪去Spring的依賴)
    • 按 XML編寫(xiě)配置類 或者直接導(dǎo)入配置類:@Import、@ImportSource
  • 十一. Spring生命周期

    這是一個(gè)大工程。

    ? 在 Spring中,由于其生命周期過(guò)于復(fù)雜,所以 Spring沒(méi)有按慣例為所有階段單獨(dú)定義方法。

    ? 其使用事件監(jiān)聽(tīng)器,我們只需要監(jiān)聽(tīng)被干預(yù)的階段即可(繼承接口實(shí)現(xiàn))。

    ? 優(yōu)點(diǎn)表現(xiàn):統(tǒng)一了管理事件流程,并用泛型區(qū)分階段。

  • 簡(jiǎn)單實(shí)現(xiàn)
  • 生命周期示意圖

    CSDN鏈接

  • [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-3QSKrg0v-1651739102961)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1m6y2cq40j20u00ufq76.jpg)]

    十二. 什么是 pom

  • POM:Project Object Model,項(xiàng)目對(duì)象模型
  • 簡(jiǎn)介:**pom既是一個(gè)XML文件,也是 Maven 工程的基本工作單元。**其包含了項(xiàng)目的基本信息,用于描述項(xiàng)目如何構(gòu)建、聲明項(xiàng)目依賴等。在運(yùn)行項(xiàng)目時(shí),Maven會(huì)在當(dāng)前目錄中查找并讀取 POM,然后獲取所需的配置信息、執(zhí)行目標(biāo)。
  • POM 中可以指定以下配置:
    • 項(xiàng)目依賴
    • 插件
    • 執(zhí)行目標(biāo)
    • 項(xiàng)目構(gòu)建 profile
    • 項(xiàng)目版本
    • 項(xiàng)目開(kāi)發(fā)者列表
    • 相關(guān)郵件列表信息
  • **注意:**所有 POM 文件都需要 project 元素和三個(gè)必需字段 groupId、artifactId、version。
  • <project xmlns = "http://maven.apache.org/POM/4.0.0"xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.companyname.project-group</groupId><artifactId>project</artifactId><version>1.0</version></project>
  • pom包細(xì)究:

    ? 總體結(jié)構(gòu)(四部分),此為阿里云下載的 SpringBoot程序結(jié)構(gòu),官方與此稍有不同。

  • 項(xiàng)目的總體信息

  • maven依賴庫(kù)

  • maven依賴庫(kù)設(shè)置

  • 構(gòu)建插件

  • 十三. 為什么會(huì)返回JSON格式數(shù)據(jù)

  • 原因:
    • 使用了 @ResponseBody注解
    • 導(dǎo)入了 Jackson JSON數(shù)據(jù)格式解析器
  • 使用其他 JSON數(shù)據(jù)格式解析器:如:GSON、fastJSON
    • 排除 Jackson依賴并導(dǎo)入其他依賴
    • 配置新環(huán)境
  • <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></exclusion></exclusions> </dependency> <!--導(dǎo)入新依賴--> <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.80</version> </dependency>

    (Spring官方對(duì) fastJSON的支持度很低,自行配置編碼格式等內(nèi)容)

    @Configuration class MyFastJsonConfig {@BeanFastJsonHttpMessageConverter fastJsonHttpMessageConverter(){FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();FastJsonConfig config = new FastJsonConfig();config.setCharset(Charset.forName("UTF-8"));config.setDateFormat("yyyy-MM-dd");config.setSerializerFeatures(SerializerFeature.WriteClassName,SerializerFeature.WriteMapNullValue,SerializerFeature.PrettyFormat,SerializerFeature.WriteNullListAsEmpty,SerializerFeature.WriteNullStringAsEmpty);converter.setFastJsonConfig(config);return converter;} } server:port: 80servlet:encoding:force-response: true

    十四. 跨域請(qǐng)求 CORS

  • 簡(jiǎn)介:

    ? CORS,Cross-Origin Resource Sharing,是由 W3C制定的一種跨域資源共享技術(shù)標(biāo)準(zhǔn),其目的是為了解決前端的跨域請(qǐng)求。它允許瀏覽器向跨源服務(wù)器,發(fā)出 XMLHttpRequest請(qǐng)求,從而克服了 AJAX只能同源使用的限制。

  • 特征:

    • 其特征是瀏覽器在發(fā)送請(qǐng)求時(shí)會(huì)攜帶 Origin標(biāo)識(shí),因?yàn)椤?跨域 ”。
    • 服務(wù)器如果支持跨域請(qǐng)求,則會(huì)檢查 client所攜帶的 Origin正確性,作出相應(yīng)回應(yīng)。如果 oringin指定的域名在許可范圍內(nèi),服務(wù)器返回的相應(yīng)數(shù)據(jù)則會(huì)多出幾個(gè)頭信息字段。

  • 2?? Spring基礎(chǔ)知識(shí)

    Spring全稱: Spring Framework

    一. 注解開(kāi)發(fā)說(shuō)明

    ? Annotation:基于注解的方式 @Component。當(dāng)我們給類注解時(shí),默認(rèn) Bean的命名空間為小寫(xiě)開(kāi)頭的全類名,如 UserMapper則為 userMapper,當(dāng)然我們也可以指定 Bean命名空間。

    二. 配置 Bean

    ? 其實(shí)總的來(lái)說(shuō),配置 Bean的方式有很多種,在SpringBoot的學(xué)習(xí)過(guò)程中我知道起碼有七種。但是在日常的使用中普遍的也就兩種:@Component注解或者 @Bean注解。

  • 說(shuō)明

    注解的方式需要事先開(kāi)啟包掃描 @ComponentScan注解。

  • IDEA使用技巧

    當(dāng)顯示這個(gè)小圖標(biāo)表示注解已生效,點(diǎn)擊可跳轉(zhuǎn)至 @Autowired被注入的地方。

  • 注意:

    當(dāng) Bean被創(chuàng)建時(shí),會(huì)首先默認(rèn)調(diào)用其無(wú)參構(gòu)造方法。

    當(dāng)為餓漢模式時(shí),運(yùn)行即調(diào)用;當(dāng)為懶漢模式時(shí),使用時(shí)才調(diào)用。

  • SpringBoot如何設(shè)置在創(chuàng)建時(shí)調(diào)用有參構(gòu)造方法?

    @Configuration + @Bean

  • 三. 配置第三方 Bean

    ? 采用配置類 @Configuration + @Bean的方式。第三個(gè)類可以指在所導(dǎo)入的 jar包中的類,它原來(lái)不是 Bean或者我們需要去配置它,但是我們并不能直接的去改寫(xiě)它,因?yàn)槔^承太過(guò)于麻煩、而且有時(shí) jar中的類會(huì)被定義為 final無(wú)法繼承。

    @Configuration public class CustomConfig {@BeanRedisTemplate getRedisTemplate(){return new RedisTemplate();} }

    四. 單例與多實(shí)例

    ? 當(dāng)我們創(chuàng)建 Bean時(shí),默認(rèn)會(huì)為我們創(chuàng)建單例 Singleton的實(shí)例:即容器初始化時(shí)創(chuàng)建 Bean,容器關(guān)閉前銷毀 Bean。

    ? Spring默認(rèn)類型是 singleton,幾乎90%以上的業(yè)務(wù)使用單實(shí)例就可以。

    ? Singleton的優(yōu)點(diǎn)是效率高;缺點(diǎn)是可能會(huì)引發(fā)單線程下的線程安全問(wèn)題。

    ? Prototype的優(yōu)點(diǎn)是不會(huì)觸發(fā)單線程安全問(wèn)題;缺點(diǎn)是每次連接請(qǐng)求都會(huì)創(chuàng)建 bean實(shí)例,請(qǐng)求數(shù)越多性能越低。而且因?yàn)閯?chuàng)建的實(shí)例導(dǎo)致頻繁垃圾回收,GC的時(shí)長(zhǎng)也相應(yīng)增加。(garbage cycle)

    多實(shí)例的創(chuàng)建:

  • @Scope: 硬編碼格式。
  • @Scope(value = "prototype") @Scope(value = "singleton") @Scope(value = "request") //一次http請(qǐng)求內(nèi)有效 @Scope(value = "session") //一個(gè)用戶會(huì)話內(nèi)有效 @Scope(value = "globalSession") //全局會(huì)話內(nèi)有效

    五. @Autowired說(shuō)明

    ? 自動(dòng)注入本身屬性: require = true

    ? 實(shí)現(xiàn)功能:在注入時(shí)忽略報(bào)錯(cuò),有則加載、無(wú)則使用默認(rèn)值。

    // 此處并不一定會(huì)加載 222,而是該 Bean不存在時(shí)才會(huì)加載 222,注意這種寫(xiě)法。 @Autowired(required = false) User user = new User(222); 屬性說(shuō)明
    @Autowired根據(jù)屬性類型自動(dòng)裝配
    @Qualifier結(jié)合@ Autowired根據(jù)屬性名稱自動(dòng)裝配
    @Resource可以根據(jù)屬性類型或?qū)傩悦Q進(jìn)行注入
    @Value普通類型屬性注入

    (但是 Spring官方不推薦使用 @Resource,因?yàn)樽⒔獠⒎?Spring官方開(kāi)發(fā),而是屬于 Javax——Java擴(kuò)展包之中的內(nèi)容)

    簡(jiǎn)單使用:

    ? 配置同類型不同名的 Bean對(duì)象。

    @Configuration public class CustomConfig {@Bean@Primary // 默認(rèn) BeanUserService get_01() {return new UserServiceImpl();}@Bean("other") // 需指定名稱才能導(dǎo)入UserService get_02() {return new UserServiceImpl();} }

    ? 利用 @Autowired + @Qualifier 進(jìn)行指定Bean的注入。

    @Autowired @Qualifier("other") UserService service;

    六. Bean的生命周期

    ? Bean也含有生命周期,利用注解(于方法上)我們可以對(duì)其進(jìn)行控制,分別在其創(chuàng)建后、銷毀前。

    ? @PostConstruct@PreDestroy

    @PostConstructvoid initial(){System.out.println("創(chuàng)建后"); }@PreDestroy void destroy(){System.out.println("銷毀前"); }

    七. 條件裝配:Bean加載控制

    ? 即 @Conditional(OnSmtpEnvCondition.class)的形式。

    ? 使用條件注解,使我們能夠更加靈活的裝載 Bean。

  • 簡(jiǎn)介:
    • @Conditional注解可以放在方法和類上。
    • 放在方法上和 @Bean一起使用,表示如果 @Conditional注解的參數(shù)類 matches方法為true這創(chuàng)建這個(gè) Bean實(shí)例,否則不創(chuàng)建。
    • 放在類上結(jié)合 @Configuration、@ComponentScan判斷被注解的類是否需要?jiǎng)?chuàng)建
    • 可以同時(shí)擁有多個(gè) @Conditional,變式多樣。
  • 簡(jiǎn)單使用
  • // 如果Spring中不存在 UsersController Bean,就加載配置 @Configuration @ConditionalOnMissingBean(Cat.class) public class Test {@Beanpublic Dog getMsg(){return new Dog();} } @ConditionalOnBean(name = "com.test.controller.UsersController") @Component("jerry") public class Cat { }

    ( 比如 @ConditionalOnMissingClass(com.pojo.yyoo) ,當(dāng)不存在此類時(shí),條件為真。)

    八. 為Bean內(nèi)的變量賦值

    ? Spring在注入一對(duì)象時(shí),對(duì)象里的變量是如何被賦值的呢?

    ? Spring會(huì)調(diào)用這些變量的 set___ ( ) 方法從而為這些變量賦值,我們可以控制此流程。

    九. Spring事務(wù)管理

  • 四大特性:原子性、隔離性、一致性、持久性
  • 底層原理:AOP面向切面編程
  • 未完待續(xù)。
  • 十. JdbcTemplate解釋

  • JDBC是Java操作數(shù)據(jù)庫(kù)的一套規(guī)范。
  • JdbcTemplate:**JDBC的模板 **,Spring封裝的 JDBC對(duì)象。
  • MyBatis是一個(gè)基于 Java的、封裝了 JDBC的持久層框架。
  • 十一. P命名空間

    ? 即存在于 XML配置文件中的擴(kuò)展寫(xiě)法(了解即可)。

    實(shí)現(xiàn)步驟:

  • 復(fù)制標(biāo)準(zhǔn)格式,改成名稱 P。

  • 直接使用

  • 十二. 關(guān)閉ApplicationContext

    ? 利用ApplicationContext獲取的對(duì)象,最后需要手動(dòng)的去關(guān)閉它。

    兩種方法:

  • try-catch語(yǔ)句
  • 強(qiáng)轉(zhuǎn) + close( ):原生的ApplicationContext中無(wú)close方法,所以這里需要強(qiáng)轉(zhuǎn)再 close。
  • 十三. 完全注解開(kāi)發(fā)

  • 要求:創(chuàng)建配置類Configuration,代替XML配置文件
  • 舉個(gè)不太恰當(dāng)?shù)睦?/li>

    十四. 獲取 Bean

    ? Spring中擁有兩種方式(并非方法)。

  • 按 ID名字獲取

    在SpringBoot中,根據(jù) @Autowired + @Qulifier 獲取

  • 按類型獲取

  • app.getBean("ByID"); app.getBean(___.class);

    十五. 導(dǎo)入其他配置項(xiàng)

    ? 兩種注解。

  • @Import:導(dǎo)入其他配置類。
  • @Import(ConfigUser.class)
  • @ImportResource:導(dǎo)入 XML文件。
  • 十六. Bean的分類

    JavaBean分為兩類:

    • 一類稱為實(shí)體類 Bean:專門(mén)存儲(chǔ)業(yè)務(wù)數(shù)據(jù)的,如 Student、User 等
    • 一類稱為業(yè)務(wù)類 Bean:指 Service 或 Dao 對(duì)象,專門(mén)用于處理業(yè)務(wù)邏輯和數(shù)據(jù)訪問(wèn)。

    3?? Spring MVC基礎(chǔ)知識(shí)

    一. MVC簡(jiǎn)介

  • 全稱:Model View Controller
  • 說(shuō)明:MVC是模型(model) - 視圖(view) - 控制器(controller)的縮寫(xiě),其是一種軟件設(shè)計(jì)規(guī)范,是一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示,三者相互分離的方法。
  • 優(yōu)點(diǎn):數(shù)據(jù)層、邏輯層、界面層相互分離,其中邏輯層來(lái)負(fù)責(zé)整體的調(diào)用,降低了程序整體的耦合性,從而可以三個(gè)人同時(shí)開(kāi)發(fā)互不沖突。同時(shí)由于擁有清晰的結(jié)構(gòu)性,也便于后期的維護(hù)。
  • 二. 衍生的 Bean注解

    ? 這些衍生出來(lái)的注解都是同一種東西的不同表現(xiàn)形式,作用完全一樣、只是為了給程序員作區(qū)分使用。

    注解@標(biāo)識(shí)為
    Component一般組件
    Controller控制器
    Service事件處理器
    Repository持久層處理器

    三. 路徑疊加

  • 其實(shí)說(shuō)的是 @RequestMapping疊加的情況,此時(shí)路徑也會(huì)直接進(jìn)行疊加。
  • @RequestMapping是 SpringMVC提供的注解,其包括 @GetMapping、@PostMapping等。
  • 以下訪問(wèn)路徑實(shí)為:/role/get
  • 四. RESTful風(fēng)格

  • 全稱:Representational State Transfer,表現(xiàn)形態(tài)轉(zhuǎn)換。

  • 分類(Spring共支持8種)

    GET(查詢)、POST(新增、保存)、PUT(修改)、DELETE(刪除)

  • 說(shuō)明:

    • 當(dāng)使用 RESTful風(fēng)格時(shí),就無(wú)路徑參數(shù)符號(hào) ? 拼接參數(shù)。
    • 當(dāng)然,RESTful風(fēng)格只是一種規(guī)范,流行于前后端分離開(kāi)發(fā)。
  • 路徑占位符

  • @GetMapping("/{name}/{pass}") void login(@PathVariable("name") String name){System.out.println("login"); }
  • 功能清單范例
  • 功能URL 地址請(qǐng)求方式
    訪問(wèn)首頁(yè)/GET
    查詢?nèi)繑?shù)據(jù)/employeeGET
    刪除/employee/2DELETE
    跳轉(zhuǎn)到添加數(shù)據(jù)頁(yè)面/toAddGET
    執(zhí)行保存/employeePOST
    跳轉(zhuǎn)到更新數(shù)據(jù)頁(yè)面/employee/2GET
    執(zhí)行更新/employeePUT

    五. @RequestMapping詳解

    ? 該注解屬性有六種,分別為 value、method、produces、consumes、header、params。

    ? 其中注意 headers作用的是請(qǐng)求頭,而 params作用的則是請(qǐng)求參數(shù)。

  • value

    指定請(qǐng)求的實(shí)際地址。

  • method

    指定請(qǐng)求的method類型, GET、POST、PUT、DELETE等。

  • produces

    指定返回內(nèi)容的類型,只有當(dāng) request請(qǐng)求頭中 Accept屬性包含該 produces指定的類型才能返回?cái)?shù)據(jù)成功,例如:accept:text/xml。

  • cousumes

    指定request請(qǐng)求提交的內(nèi)容類型(Content-Type),例如application/json, text/html等。

  • headers

    指定request請(qǐng)求中必須包含某些指定的請(qǐng)求頭header的值,才能讓該方法處理請(qǐng)求。

    例如:Host=127.0.0.1

    “header”:要求請(qǐng)求映射所匹配的請(qǐng)求必須攜帶header請(qǐng)求頭信息

    “!header”:要求請(qǐng)求映射所匹配的請(qǐng)求必須不能攜帶header請(qǐng)求頭信息

    “header=value”:要求請(qǐng)求映射所匹配的請(qǐng)求必須攜帶header請(qǐng)求頭信息且header=value

    “header!=value”:要求請(qǐng)求映射所匹配的請(qǐng)求必須攜帶header請(qǐng)求頭信息且header!=value

  • params

    指定request請(qǐng)求地址中必須包含某些參數(shù)值,方法才處理,否則拒絕處理。

    ----params = “key1”==:表示請(qǐng)求必須包含名為key1的請(qǐng)求參數(shù);
    ----params = “!key1”:表示請(qǐng)求不能包含名為key1的請(qǐng)求參數(shù);
    ----params = “key1 != value1”:表示請(qǐng)求必須包含名為key1的請(qǐng)求參數(shù),但是其值不能是value1;
    ----params = {“key1 = value1”, “key2”}:==表示請(qǐng)求必須包含名為key1和key2兩個(gè)請(qǐng)求參數(shù),且key1的值必須為value1;

  • params = {"username","password!=123456"}

    六. 路徑 ant風(fēng)格

    ? SpringMVC支持 ant風(fēng)格的路徑,即支持 ant風(fēng)格的通配符,三種

    符號(hào)表意
    單個(gè)字符
    *0個(gè)或多個(gè)字符
    **一層或者多層目錄

    七. 非 RESTful風(fēng)格說(shuō)明

    ? 本節(jié)將展示當(dāng)我們不采用 RESTful風(fēng)格時(shí)的情況。

  • 一般使用(參數(shù)同名時(shí))

    形參參數(shù)名應(yīng)與瀏覽器傳過(guò)來(lái)的參數(shù)名一樣,并不使用 @PathVariable路徑參數(shù)注解。

    在該例中,瀏覽器會(huì)跳轉(zhuǎn)至 /static/uuu.html頁(yè)面(MVC自動(dòng)解析跳轉(zhuǎn))。

  • 可變長(zhǎng)參數(shù)

    最后環(huán)節(jié),使用數(shù)組接收可變長(zhǎng)參數(shù)。

  • @RequestParam參數(shù)

    當(dāng)形參參數(shù)名與瀏覽器傳過(guò)來(lái)的參數(shù)不一致時(shí),使用注解來(lái)指定。

    required:是否必須

    name:名字

    defaultValue:當(dāng)不存在時(shí),則使用默認(rèn)值。(結(jié)合 required = false 使用)

  • 八. 域共享對(duì)象

  • 實(shí)例:在 url的跳轉(zhuǎn)中實(shí)現(xiàn)數(shù)據(jù)的共享。

  • 要求:既要實(shí)現(xiàn)完整功能,又要范圍最小。

  • 5種方式

    • 原生 Servlet:request.setAttribute( key , value ) + EL表達(dá)式。
    • ModelAndView
    • ModelMap
    • HttpSession對(duì)象
    • Application對(duì)象

  • 九. ModelAndView

  • 說(shuō)明

    ModelAndView 統(tǒng)一實(shí)現(xiàn)了 Model對(duì)象和 View對(duì)象的功能。

    Model 主要用于向請(qǐng)求域共享數(shù)據(jù),其本身是 Map的子類,擁有相應(yīng)功能。

    View 主要用于設(shè)置視圖實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)。

  • 注意

    ? 當(dāng)未配置其他解析器或者為使用 @ResponseBody注解時(shí),默認(rèn)使用的是SpringMVC解析器,而SpringMVC解析器會(huì)返回 ModelAndView對(duì)象。

  • 實(shí)現(xiàn)原理

    ? 當(dāng)控制器處理完請(qǐng)求后,通常控制器會(huì)將包含視圖名稱以及一些模型屬性的 ModelAndView對(duì)象返回給 DispatcherServlet。因此,在控制器中會(huì)構(gòu)造一個(gè) ModelAndView對(duì)象

  • 數(shù)據(jù)共享:直接使用方法。

  • addObject(String attributeName, Object attributeValue)
  • 頁(yè)面跳轉(zhuǎn)
  • @GetMapping ModelAndView get() {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("uuu.html");return modelAndView; }

    十. 請(qǐng)求響應(yīng)擴(kuò)展

  • 簡(jiǎn)介

    正式名稱:HttpMessageConverter 報(bào)文信息轉(zhuǎn)換器

    將請(qǐng)求報(bào)文轉(zhuǎn)換為Java對(duì)象,或?qū)ava對(duì)象轉(zhuǎn)換為響應(yīng)報(bào)文。

  • 四種類型:

  • @RequestBody

    ? 該注解加在Controller 的處理方法的形參上,作用是將json格式的數(shù)據(jù)轉(zhuǎn)為java對(duì)象

    ? 作用于 Post請(qǐng)求,獲取請(qǐng)求體。

    @RequestBody String requestBody @RequestBody User user_date
  • RequestEntity對(duì)象

    ? 獲取的是整個(gè)請(qǐng)求頭+請(qǐng)求體,getBody( ) 獲取請(qǐng)求體,getHeaders( )獲取請(qǐng)求頭。

    ? **需要理解的是,HttpServletRequest是 Servlet技術(shù),而 RequestEntity是 SpringMVC技術(shù)。**使用 RequestEntity而不使用 HttpServletRequest。

    用法:只要控制器方法的形參中設(shè)置該類型,其就會(huì)自動(dòng)賦值。

    public String test(RequestEntity reqEntity){// }
  • @ResponseBody

    ? 該注解使用在Controller 方法上的 。將方法的返回值通過(guò)適當(dāng)?shù)霓D(zhuǎn)換器(如 Jackson)轉(zhuǎn)換為指定的格式之后,寫(xiě)入到 response 對(duì)象的 body 區(qū),通常用來(lái)給客戶端返回 JSON 數(shù)據(jù)或者是 XML 數(shù)據(jù)。

    ? 當(dāng)方法上面沒(méi)有寫(xiě) ResponseBody 時(shí),底層會(huì)將方法的返回值封裝為 ModelAndView 對(duì)象(原此);需要注意的是,在使用此注解之后不會(huì)再走試圖處理器,而是直接將數(shù)據(jù)寫(xiě)入到輸入流中,他的效果等同于通過(guò) response 對(duì)象輸出指定格式的數(shù)據(jù)。

  • ResponseEntity對(duì)象

    ? 可以定義返回的 HttpStatus(狀態(tài)碼)和 HttpHeaders(響應(yīng)頭) 和響應(yīng)體 body,當(dāng)形參出現(xiàn)此時(shí),ModelAndView失效、@ResponseBody注解也失效。

    @RequestMapping("/downExcel") @ResponseBody public String downExcel(HttpServletResponse response) {// response邏輯操作OutputStream os = response.getOutputStream();return "" }
  • 十一. MVC工作流程

    ? 用戶通過(guò)視圖層發(fā)送請(qǐng)求到服務(wù)器,在服務(wù)器中請(qǐng)求被Controller接收,Controller調(diào)用相應(yīng)的Model層處理請(qǐng)求,處理完畢將結(jié)果返回到Controller,Controller再根據(jù)請(qǐng)求處理的結(jié)果找到相應(yīng)的View視圖,渲染數(shù)據(jù)后最終響應(yīng)給瀏覽器。

    十二. 文件下載

  • 本質(zhì):文件復(fù)制。
  • SpringMVC文件下載流程:
    • 先通過(guò)輸入流( 例如InputStream )將文件讀取到Java程序中。
    • 建立 byte[ ] 數(shù)組,將輸入流讀取到的所有數(shù)據(jù)都存儲(chǔ)到byte [ ] 數(shù)組。
    • 向客戶端響應(yīng)byte[ ]數(shù)組或者類似 **ResponseEntity<byte[ ]>**的響應(yīng)類型。
  • 文件下載必須要設(shè)置的請(qǐng)求頭(設(shè)置類型)
  • headers.add("Content-Disposition", "attachment;filename=1.jpg");
  • 使用 ResponseEntity實(shí)現(xiàn)下載文件的功能(未跑通)
  • @RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {ServletContext servletContext = session.getServletContext();//獲取服務(wù)器中文件的真實(shí)路徑String realPath = servletContext.getRealPath("/static/img/1.jpg");InputStream is = new FileInputStream(realPath);byte[] bytes = new byte[is.available()];//將流讀到字節(jié)數(shù)組中is.read(bytes);//創(chuàng)建HttpHeaders對(duì)象設(shè)置響應(yīng)頭信息MultiValueMap<String, String> headers = new HttpHeaders();//設(shè)置要下載方式以及下載文件的名字headers.add("Content-Disposition", "attachment;filename=1.jpg");HttpStatus statusCode = HttpStatus.OK;ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);//關(guān)閉輸入流is.close();return responseEntity; }
  • 實(shí)踐:

    ? 以上代碼我在 IDEA與服務(wù)器上并未跑通,于是我嘗試了別的方法。

    ? 需要說(shuō)明的是:所有資源都放在/resource/static/里。

    • IDEA跑通,服務(wù)器跑通。
    @RestController @RequestMapping("/download") public class DownloadController {@GetMapping("{fileName}")ResponseEntity down(@PathVariable("fileName") String fileName) throws Exception {InputStream file = ClassUtils.getDefaultClassLoader().getResourceAsStream("static/" + fileName);byte[] data = new byte[file.available()];file.read(data);HttpHeaders headers = new HttpHeaders();headers.add("Content-Disposition", "attachment;filename=" + fileName);ResponseEntity responseEntity = new ResponseEntity<>(data, headers, HttpStatus.OK);return responseEntity; }}
    • IDEA跑通,服務(wù)器未跑通。

      在路徑兩處多了感嘆號(hào) ! ,暫時(shí)不明白原因是什么。

    String realPath =ResourceUtils.getURL("classpath:static/").getPath()+ fileName;

    十三. 文件上傳

  • 本質(zhì):文件復(fù)制。

  • 上傳功能必需請(qǐng)求頭:

    multipart/form-data,即標(biāo)明為以二進(jìn)制方式上傳數(shù)據(jù),而不是key-value。

  • <form method="post" enctype="multipart/form-data" action="/upload">圖片:<input type="file"><input type="submit"> </form>
  • 上傳操作要導(dǎo)入額外的依賴包 Apache Commons FileUpload
  • <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version> </dependency>
  • 范例代碼
  • @RequestMapping("/testUp") public String testUp(MultipartFile photo, HttpSession session) throws IOException {//獲取上傳的文件的文件名String fileName = photo.getOriginalFilename();//處理文件重名問(wèn)題,UUIDString hzName = fileName.substring(fileName.lastIndexOf("."));fileName = UUID.randomUUID().toString() + hzName;//獲取服務(wù)器中photo目錄的路徑ServletContext servletContext = session.getServletContext();String photoPath = servletContext.getRealPath("photo");File file = new File(photoPath);if(!file.exists()){file.mkdir();}String finalPath = photoPath + File.separator + fileName;//實(shí)現(xiàn)上傳功能photo.transferTo(new File(finalPath));return "success"; }
  • 簡(jiǎn)單實(shí)踐

    該案例會(huì)將文件上傳至與當(dāng)前項(xiàng)目總文件夾 平齊的文件夾。

  • @RestController @RequestMapping("/upload") public class UploadController {@PostMappingString upload(MultipartFile file, HttpSession session) throws IOException {String filename = file.getOriginalFilename(); String fileType = filename.substring(filename.lastIndexOf(".")); filename = filename.substring(0,filename.indexOf("."))+ "-" + UUID.randomUUID().toString()+fileType;String realPath = ResourceUtils.getURL("images").getPath(); File io_file=new File(realPath); if (!io_file.exists()){io_file.mkdirs(); }file.transferTo(new File(finalPath));return "success"; }}

    十四. 攔截、過(guò)濾、分發(fā)器總結(jié)

  • 英文名稱

    • 攔截器 interceptor:攔截Controller,分為前后攔截器。
    • 過(guò)濾器 Filter
    • 分發(fā)器 DispatcherServlet
  • 示意圖:

  • 十五. @RequestParam、@PathVariable區(qū)別

    ? @RequestParam,@PathVariable 之間的區(qū)別。

    ? @RequestParam 和 @PathVariable 注解都是用于從 request中接收請(qǐng)求,兩個(gè)都可以接收參數(shù)。關(guān)鍵點(diǎn)不同的是 @RequestParam 是從request里面拿取值,而 @PathVariable 是從一個(gè) URI模板里面來(lái)填充。

    • 用@RequestParam:/login?name=uu&pass=123
      • defaultValue 如果本次請(qǐng)求沒(méi)有攜帶這個(gè)參數(shù),或者參數(shù)為空,那么就會(huì)啟用默認(rèn)值
      • name 綁定本次參數(shù)的名稱,要跟URL上面的一樣
      • required 這個(gè)參數(shù)是不是必須的
      • value 跟name一樣的作用,是name屬性的一個(gè)別名**(震驚)**
    • 用@PathVariable:/login/uu/123
      • name-要綁定到的路徑變量的名稱
      • required-指示路徑變量是否為必需
      • value 跟name一樣的作用,是name屬性的一個(gè)別名

    十六. 視圖解析器

  • 簡(jiǎn)介:

    SpringMVC視圖的種類很多,默認(rèn)有轉(zhuǎn)發(fā)視圖和重定向視圖。

    但這必須不能存在@ResponseBody注解。

    存在@ResponseBody注解時(shí),就關(guān)乎SpringBoot下頁(yè)面的跳轉(zhuǎn)問(wèn)題,具體使用 ModelAndView。

  • 關(guān)注點(diǎn):Themleaf好像已經(jīng)很少使用。

  • 轉(zhuǎn)發(fā)視圖

    ? SpringMVC中默認(rèn)的轉(zhuǎn)發(fā)視圖是 InternalResourceView

    ? 當(dāng)控制器方法中所設(shè)置的視圖名稱以"forward:"為前綴時(shí),會(huì)創(chuàng)建InternalResourceView視圖,此時(shí)的視圖名稱不會(huì)被SpringMVC配置文件中所配置的視圖解析器解析,而是會(huì)將前綴"forward:"去掉,剩余部分作為最終路徑通過(guò)轉(zhuǎn)發(fā)的方式實(shí)現(xiàn)跳轉(zhuǎn)

  • @RequestMapping("/testForward") public String testForward(){return "forward:/testHello"; }
  • 重定向視圖

    ? SpringMVC中默認(rèn)的重定向視圖是 RedirectView

    ? 當(dāng)控制器方法中所設(shè)置的視圖名稱以"redirect:"為前綴時(shí),創(chuàng)建RedirectView視圖,此時(shí)的視圖名稱不會(huì)被SpringMVC配置文件中所配置的視圖解析器解析,而是會(huì)將前綴"redirect:"去掉,剩余部分作為最終路徑通過(guò)重定向的方式實(shí)現(xiàn)跳轉(zhuǎn)

  • @RequestMapping("/testRedirect") public String testRedirect(){return "redirect:/testHello"; }

    十七. SpringMVC執(zhí)行流程

    **前置知識(shí):**SpringMVC常用組件

    • DispatcherServlet:前端控制器,不需要工程師開(kāi)發(fā),由框架提供

    作用:統(tǒng)一處理請(qǐng)求和響應(yīng),整個(gè)流程控制的中心,由它調(diào)用其它組件處理用戶的請(qǐng)求

    • HandlerMapping:處理器映射器,不需要工程師開(kāi)發(fā),由框架提供

    作用:根據(jù)請(qǐng)求的url、method等信息查找Handler,即控制器方法

    • Handler:處理器,需要工程師開(kāi)發(fā)

    作用:在DispatcherServlet的控制下Handler對(duì)具體的用戶請(qǐng)求進(jìn)行處理

    • HandlerAdapter:處理器適配器,不需要工程師開(kāi)發(fā),由框架提供

    作用:通過(guò)HandlerAdapter對(duì)處理器(控制器方法)進(jìn)行執(zhí)行

    • ViewResolver:視圖解析器,不需要工程師開(kāi)發(fā),由框架提供

    作用:進(jìn)行視圖解析,得到相應(yīng)的視圖,例如:ThymeleafView、InternalResourceView、RedirectView

    • View:視圖

    作用:將模型數(shù)據(jù)通過(guò)頁(yè)面展示給用戶

    SpringMVC的執(zhí)行流程

  • 用戶向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求經(jīng)過(guò)Filter后被 SpringMVC 前端控制器 DispatcherServlet捕獲。
  • DispatcherServlet對(duì)請(qǐng)求 URL進(jìn)行解析,得到請(qǐng)求資源標(biāo)識(shí)符 URI,判斷請(qǐng)求 URI對(duì)應(yīng)的映射:

    不存在

    • 判斷是否配置了mvc:default-servlet-handler

      沒(méi)配置:則控制臺(tái)報(bào)映射查找不到,客戶端展示404錯(cuò)誤

      有配置:則訪問(wèn)目標(biāo)資源(一般為靜態(tài)資源,如:JS,CSS,HTML),找不到客戶端也會(huì)展示404錯(cuò)誤

    存在(此處的 Handler為 Controller的同一對(duì)象不同說(shuō)法)

    • 根據(jù)該URI,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對(duì)象(包括Handler對(duì)象以及Handler對(duì)象對(duì)應(yīng)的攔截器),最后以 HandlerExecutionChain執(zhí)行鏈對(duì)象的形式返回。

    • DispatcherServlet 根據(jù)獲得的 Handler,選擇一個(gè)合適的 HandlerAdapter。

    • 如果成功獲得 HandlerAdapter,此時(shí)將開(kāi)始執(zhí)行攔截器的 preHandler(…)方法【正向】

    • 提取 Request中的模型數(shù)據(jù),填充Handler入?yún)?#xff0c;開(kāi)始執(zhí)行 Handler方法,處理請(qǐng)求。在填充 Handler的入?yún)⑦^(guò)程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:

      a) HttpMessageConveter: 將請(qǐng)求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對(duì)象,將對(duì)象轉(zhuǎn)換為指定的響應(yīng)信息

      b) 數(shù)據(jù)轉(zhuǎn)換:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer、Double等

      c) 數(shù)據(jù)格式化:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)格式化。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等

      d) 數(shù)據(jù)驗(yàn)證: 驗(yàn)證數(shù)據(jù)的有效性(長(zhǎng)度、格式等),驗(yàn)證結(jié)果存儲(chǔ)到BindingResult或Error中

  • Handler執(zhí)行完成后,向DispatcherServlet 返回一個(gè)ModelAndView對(duì)象。

  • 此時(shí)將開(kāi)始執(zhí)行攔截器的postHandle(…)方法【逆向】。

  • 根據(jù)返回的ModelAndView(此時(shí)會(huì)判斷是否存在異常:如果存在異常,則執(zhí)行HandlerExceptionResolver進(jìn)行異常處理)選擇一個(gè)適合的ViewResolver進(jìn)行視圖解析,根據(jù)Model和View,來(lái)渲染視圖。

  • 渲染視圖完畢執(zhí)行攔截器的afterCompletion(…)方法【逆向】。

  • 將渲染結(jié)果返回給客戶端。

  • 十八. Thymeleaf說(shuō)明

  • 簡(jiǎn)介:

    • 在目前的企級(jí)應(yīng)用開(kāi)發(fā)中前后端分離是趨勢(shì),但視圖層技術(shù)仍有一席之地。
    • Spring Boot 官方推薦使用的模板引擎是 Thymeleaf,Spring Boot 提供了 Thymeleaf自動(dòng)配置解決方案,因而Spring Boot 中使用 Thymeleaf非常方便。
    • 如果開(kāi)發(fā)者使用的是前后端分離技術(shù),那么開(kāi)發(fā)過(guò)程不需要整合視圖層技術(shù)。
  • 默認(rèn)配置說(shuō)明

    路徑:classpath/template/____,后綴 html。

  • 實(shí)現(xiàn)步驟:

    • 導(dǎo)pom start包
    • yml配置屬性
    • controller中使用
  • <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> spring:thymeleaf:prefix: classpath:/template/encoding: UTF-8suffix: .html
  • 實(shí)現(xiàn)說(shuō)明:

    在 cotroller中使用后,會(huì)默認(rèn)返回 ModelAndView對(duì)象。

    SpringMVC返回的也是 ModelAndView對(duì)象,兩者同為視圖解析器。


  • 4?? SpringBoot小知識(shí)點(diǎn)

  • **static與 template目錄:**static中的資源不受保護(hù),可以直接通過(guò) url定位來(lái)訪問(wèn),而templates中的資源是受保護(hù)的。

  • SpringBoot工程在IDEA下需要聯(lián)網(wǎng)進(jìn)行。

  • SpringBoot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程。

  • SpringBoot只是簡(jiǎn)化Spring與SpringMVC的簡(jiǎn)化開(kāi)發(fā),MybatisPlus也是在簡(jiǎn)化Mybatis,本質(zhì)還是SSM框架。

  • Spring Boot 不支持同時(shí)在配置中啟動(dòng) HTTP HTTPS 。

  • 一些專業(yè)名詞

    • 數(shù)據(jù)源:DruidDataSource
    • 持久化技術(shù):Mybatis、MybatisPlus
    • 數(shù)據(jù)庫(kù):MySQL
  • 三種內(nèi)嵌的數(shù)據(jù)源

    數(shù)據(jù)源默認(rèn)存在的,并不一定需要 Druid。

  • HikariCP(SpringBoot默認(rèn)數(shù)據(jù)源)
  • Tomcat的 DataSource
  • Common的 DBCP
  • 三種內(nèi)嵌數(shù)據(jù)庫(kù)(了解)

    不過(guò)到真正上線的時(shí)候還是要切換到正式數(shù)據(jù)庫(kù),而且體驗(yàn)并不是很好,棄用。

  • H2
  • HSQL
  • Derby
  • MyBatis是一個(gè)基于 Java的、封裝了 JDBC的持久層框架,其底層使用 JDBC來(lái)編寫(xiě)。

  • JS等前端庫(kù)可通過(guò) pom導(dǎo)入。

    <dependency><groupId>org.webjars</groupId><artifactId>vue</artifactId><version>2.6.14</version> </dependency>
  • Controller路徑命名規(guī)則:

    常用復(fù)數(shù)形式表示,如 users、employees等。

  • 配置文件放在哪?

    在Maven的結(jié)構(gòu)下,配置文件均放在resource目錄里。

  • yml配置信息如何記?

  • 只需要你記得其中幾個(gè)關(guān)鍵字,然后在 IDEA中敲一敲就能知道個(gè)大概。
  • 未知編程思想

    當(dāng)遇到陌生方法調(diào)用時(shí),只需觀察其形參與返回值,在大多數(shù)情況下便可了解其用法。

  • html表單說(shuō)明

    html中的 form表單只能發(fā)送 Get或者 Post請(qǐng)求,并不能發(fā)送其他請(qǐng)求。

  • Tomcat思想:萬(wàn)物皆對(duì)象。

  • JSON數(shù)據(jù)格式說(shuō)明:一共只有兩種格式。

  • - 對(duì)象:{ } - 數(shù)組:[ ]
  • 寶塔小坑

    • 阿里云與寶塔均存在端口攔截機(jī)制,需要在兩邊都打開(kāi)才能訪問(wèn)。
    • 即使我在寶塔里部署 SpringBoot項(xiàng)目時(shí)設(shè)置了隨機(jī)端口映射,寶塔也不會(huì)默認(rèn)開(kāi)啟端口。
  • 關(guān)于 long類型

  • **long類型**本身描述的時(shí)間單位為**毫秒ms**,熟記。

    5?? SpringBoot基礎(chǔ)知識(shí)

    一. 初始項(xiàng)目結(jié)構(gòu)

    ├── HELP.md ├── README.md ├── catcat.iml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src├── main│ ├── java│ │ └── com│ │ └── thinkstu│ │ └── catcat│ │ └── CatcatApplication.java│ └── resources│ ├── application.properties│ ├── static│ └── templates└── test└── java└── com└── thinkstu└── catcat└── CatcatApplicationTests.java

    二. delete、put請(qǐng)求說(shuō)明

    ? 部分瀏覽器只支持發(fā)送 get和 post請(qǐng)求,那么在 SpringBoot中該如何發(fā)送 put和 delete請(qǐng)求呢?

    ? SpringMVC 提供了 HiddenHttpMethodFilter 幫助我們將 POST 請(qǐng)求轉(zhuǎn)換為 DELETE 或 PUT 請(qǐng)求,SpringBoot中默認(rèn)存在此配置類。

    使用要求:

    • 瀏覽器的請(qǐng)求方式必須為post
    • 瀏覽器必須傳輸請(qǐng)求參數(shù)_method

    ? 滿足以上條件,HiddenHttpMethodFilter 過(guò)濾器就會(huì)將當(dāng)前請(qǐng)求的請(qǐng)求方式轉(zhuǎn)換為請(qǐng)求參數(shù)_method的值,因此請(qǐng)求參數(shù)_method的值才是最終的請(qǐng)求方式。

    三. jar包與 war包的區(qū)別

  • 簡(jiǎn)介:

    ? jar包和war包都可以看成壓縮文件,都可以用解壓軟件打開(kāi),jar包和war包都是為了項(xiàng)目的部署和發(fā)布,通常在打包部署的時(shí)候,會(huì)在里面加上部署的相關(guān)信息。

  • 簡(jiǎn)單區(qū)別:

    • JAR(Java Archive,Java 歸檔文件),是一個(gè)完整的項(xiàng)目結(jié)構(gòu),以流行的 ZIP 文件格式為基礎(chǔ),jar包本質(zhì)上就是 zip包,只是額外附加了一些固定的描述文件。
    • war包不是一個(gè)完整的項(xiàng)目結(jié)構(gòu),需要按照傳統(tǒng)的方式去進(jìn)行部署。war包是 Sun提出的一種 web應(yīng)用程序格式,與 jar類似,是很多文件的壓縮包。
  • 根本區(qū)別:

    ? JAR文件的目的是把類和相關(guān)的資源封裝到壓縮的歸檔文件中,而對(duì)于WAR文件來(lái)說(shuō),一個(gè)WAR文件代表了一個(gè)Web應(yīng)用程序,它可以包含 Servlet、HTML頁(yè)面、Java類、圖像文件,以及組成Web應(yīng)用程序的其他資源,而不僅僅是類的歸檔文件。

  • 四. start 與 parent的區(qū)別

  • 說(shuō)明:Start與 parent均在 pom文件中。
  • Start指定對(duì)應(yīng)包。
  • parent指定具體版本。
  • <!-- Start示例 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId> </dependency><!-- 對(duì)應(yīng)parent --> <jetty.version>9.4.35.v20201120</jetty.version>

    五. @SpringBootApplication說(shuō)明

  • 簡(jiǎn)介:

    位于主啟動(dòng)程序上,負(fù)責(zé)配置主程序

    其實(shí)是一個(gè) SpringBoot Configuration( SpringBoot Configuration下面是 @Configuration)。

  • @SpringBootApplication public class Test01Application {public static void main(String[] args) {SpringApplication.run(Test01Application.class, args);}}

    六. #{ }與 ${ }說(shuō)明

  • 簡(jiǎn)介:

    • #{ }用來(lái)獲取 Bean類的變量值。
    • ${ }用來(lái)獲取 yml文件中的變量值。
  • 范例:

    加載名為users的這個(gè)Bean的cycle屬性值

  • @Scheduled(cron = "0/#{users.cycle} * * * * ?") @Data @Component("users") public class Users{Integer cycle=10; }

    七. @ControllerAdvice說(shuō)明

    ? @ControllerAdvice :全局?jǐn)?shù)據(jù)處理,是@Controller 的加強(qiáng)版。

    ? @ControllerAdvice 主要用來(lái)處理全局?jǐn)?shù)據(jù),一般搭配@ExceptionHandler、@ModelAttribute 及@InitBinder 使用。而RESTControllerAdvice就是Restful風(fēng)格的ControllerAdvice;

    八. 臨時(shí)配置說(shuō)明

  • 臨時(shí)配置既可以在命令行中修改,也可以在代碼中提前寫(xiě)好。
  • java -jar xxx.java --server.port 8080

  • 禁止臨時(shí)配置
  • 有時(shí)我們會(huì)為了安全,禁止其他人在運(yùn)行我們的程序時(shí)添加臨時(shí)屬性。

    方式:阻止main主程序中的args參數(shù)傳到SpringApplication。

    九. yml格式說(shuō)明

  • 說(shuō)明:重?cái)?shù)據(jù)、輕格式。
  • 基本語(yǔ)法格式:
    • 屬性 與 屬性值之間用冒號(hào) : 分隔,屬性值之前要加空格

    • 大小寫(xiě)敏感,禁止同名,#表注釋。

    • 多屬性值(數(shù)組)之間用**小橫桿-**分隔

    • 使用縮進(jìn)表示層級(jí)關(guān)系,同層級(jí)左側(cè)對(duì)齊,只允許使用空格。

    • 屬性值支持轉(zhuǎn)義字符,但必須用雙引號(hào)括起來(lái)。如:name: "/t name /n"

  • 簡(jiǎn)單書(shū)寫(xiě)實(shí)例
  • #表示對(duì)象,多實(shí)例(數(shù)組)用 - 符號(hào)分隔 users:- name: zhangsanage: 22city: 北京- name: wangwuage: 23city: 海南 #或者 users:- name: zhangsanage: 22city: 北京- name: wangwuage: 23city: 海南#或者 (注:外層中括號(hào)表數(shù)組,里層大括號(hào)表具體對(duì)象) users: users2: [{name: zhangsan,age: 22},{name: wangwu,age: 23}]
  • yml格式中互相引用
  • name: duck users: ${name}
  • 特殊寫(xiě)法
  • version: @project.version@

    表示獲取該程序的version屬性,@ @包裹、輸入會(huì)有提示。

    十. 松散綁定說(shuō)明

  • 簡(jiǎn)介:

    松散綁定是 Spring為了兼容各種編程愛(ài)好者而制定的規(guī)則。

    我們并不需要使用,但是要了解、知道它的存在,其有時(shí)會(huì)導(dǎo)致程序出現(xiàn) error。

  • 注意點(diǎn):

    • 部分支持、部分不支持,使用駝峰命名法永遠(yuǎn)沒(méi)有錯(cuò)。
    • @ConfigurationProperties支持松散綁定,@Value不支持。
  • 范例:

  • ? yml中寫(xiě)的是 dataSource,但是在代碼中以下形式都能綁定上數(shù)據(jù)。

    @ConfigurationProperties(prefix = "datasource") @ConfigurationProperties(prefix = "Data_Source") @ConfigurationProperties(prefix = "Data-Source") // 羊肉串模式 //等等

    6?? SpringBoot常用操作

    一. 頁(yè)面跳轉(zhuǎn)

    ? 在 SpringBoot條件下,利用 ModelAndView實(shí)現(xiàn)。

    二. 注解方式獲取請(qǐng)求頭

    @RequestHeader,Spring中常用方式,非原生的方式。

    經(jīng)過(guò)觀察,其注解的參數(shù)與 @RequestParam一樣。

    三. 注解方式獲取Cookie

    @CookieValue,Spring中常用方式,非原生的方式。

    @CookieValue注解一共有三個(gè)屬性:value、required、defaultValue,用法同@RequestParam

    四. 編碼格式修改

    ? SpringBoot默認(rèn)的編碼格式是 UTF-8 (寫(xiě)在底層源碼中)。

    有三種方式可以定制編碼格式。

  • yml配置

    直接查找 endoding就可以顯現(xiàn)所有的內(nèi)容。

  • server:servlet:encoding:charset: UTF-8
  • Filter 過(guò)濾器配置

    原理:Filter是瀏覽器發(fā)送的請(qǐng)求接觸到的第一層服務(wù)器端應(yīng)用。 (代碼省略)

  • 配置類 配置
  • 五. 發(fā)送郵件

  • 三個(gè)郵件協(xié)議

    • SMTP:simple mail transfer protocol 簡(jiǎn)單郵件傳輸協(xié)議,發(fā)送郵件
    • POP3:post office protocol -Version 3 第3代郵局協(xié)議,接受郵件
    • IMAP:Internet mail access protocol 互聯(lián)網(wǎng)消息協(xié)議,用來(lái)替代IMAP,接受郵件

    POP3與IMAP的不同點(diǎn):**首先要得知,**我在這里所說(shuō)的采用郵件協(xié)議為,全部在第三方軟件中采用。采用POP3時(shí),郵件刪除等操作不會(huì)同步,即使你在第三方郵件系統(tǒng)刪除了某封郵件,但是在原郵件系統(tǒng)中并不會(huì)執(zhí)行刪除操作。而采用IMAP就是為了改進(jìn)這一點(diǎn),實(shí)現(xiàn)了同步的操作。

  • 簡(jiǎn)單實(shí)現(xiàn)三步走:

    • 導(dǎo)包:spring-boot-starter-mail。
    • 配置信息(服務(wù)器host、賬號(hào)、授權(quán)碼等)
    • 代碼實(shí)現(xiàn)(自動(dòng)注入JavaMailSender類)
  • 范例:

    發(fā)送簡(jiǎn)單郵件

  • <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency> spring:mail:host: smtp.qq.comusername: you_email@qq.compassword: "Authorized code"default-encoding: UTF-8 @Autowired JavaMailSender sender;@Test void sendEmail(){SimpleMailMessage msg = new SimpleMailMessage();String from="Your email@qq.com";msg.setFrom(from+"(自定義發(fā)送昵稱)"); //小括號(hào)里有內(nèi)容~msg.setTo("To email@qq.com");msg.setSubject("標(biāo)題");msg.setText("內(nèi)容");sender.send(msg); }

    ? **發(fā)送復(fù)雜郵件:**html格式、附件等

    • 將 SimpleMailMessage替換成 MimeMessage
    • 借助于 MimeMessageHelper創(chuàng)建郵件內(nèi)容
    @Autowired JavaMailSender sender; @org.junit.jupiter.api.Test void sendEmail() throws MessagingException {MimeMessage msg= sender.createMimeMessage();MimeMessageHelper msgHelper=new MimeMessageHelper(msg,true);msgHelper.setFrom("Your email@qq.com(哇哇哇)");msgHelper.setTo("To email@qq.com");msgHelper.setText("<a href='http://baidu.com'>鏈接</a>",true);String file="src/main/resources/application.yml";msgHelper.addAttachment("application.yml", new File(file));sender.send(msg);}
  • 郵件中的SSL加密

    ? 發(fā)送郵件或者接受郵件時(shí)我們可以配置SSL加密,具體要去郵件提供商那邊獲取。

    ? 例如對(duì)于騰訊,SSL端口為465或者587,首先開(kāi)啟 SSL然后再配置端口。

  • 六. Scheduled定時(shí)任務(wù)

  • 簡(jiǎn)介:Spring注解整合的方式只適用于較簡(jiǎn)單的情況,復(fù)雜業(yè)務(wù)使用 Quartz
  • 實(shí)現(xiàn)步驟:
    • 啟動(dòng)類上開(kāi)啟
    • 方法上調(diào)用
  • @EnableScheduling @Component public class Test {@Scheduled(cron = "0/5 * * * * ?")void print(){System.out.println("+----+--------+");} }
  • yml額外配置:task擁有兩組配置,我們選擇 sheduling
  • task:scheduling:pool:size: 10 #線程池?cái)?shù)量,默認(rèn)只為1。shutdown:await-termination: false #關(guān)閉時(shí)是否等待所有完成await-termination-period: 10s #最大等待時(shí)間
  • @Scheduled 注解可以利用 @Value形式從 yml中取值
  • @Scheduled(cron = "0/${a.b.c:10} * * * * ?")

    七. Cron格式編寫(xiě)指南

  • 簡(jiǎn)介:

    • 邏輯反人類
    • 在線驗(yàn)證網(wǎng)站:鏈接
  • 簡(jiǎn)單編寫(xiě)思想

    調(diào)整的時(shí)間順序,思維應(yīng)該順著從小到大

  • 編寫(xiě)規(guī)則

    秒數(shù):

    • 范圍 0~59 ,不允許為空值,若值不合法,調(diào)度器將拋出 SchedulerException異常
    • ***** 表每隔1秒鐘觸發(fā);
    • , 表在指定的秒數(shù)觸發(fā),比如"0,15,45"代表0秒、15秒和45秒時(shí)觸發(fā)任務(wù)
    • - 表在指定范圍內(nèi)觸發(fā),比如"25-45"代表從25秒開(kāi)始觸發(fā)到45秒結(jié)束觸發(fā),每隔1秒觸發(fā)1次
    • / 表觸發(fā)步進(jìn)(step),**"/“前面的值代表初始值(”“等同"0”),后面的值代表偏移量。**比如"0/20"或者"/20"代表從0秒鐘開(kāi)始,每隔20秒鐘觸發(fā)1次,即0秒觸發(fā)1次,20秒觸發(fā)1次,40秒觸發(fā)1次;"5/20"代表5秒觸發(fā)1次,25秒觸發(fā)1次,45秒觸發(fā)1次;"10-45/20"代表在[10,45]內(nèi)步進(jìn)20秒命中的時(shí)間點(diǎn)觸發(fā),即10秒觸發(fā)1次,30秒觸發(fā)1次。

    純數(shù)字系列:

    基于系統(tǒng)時(shí)間,比如 5即代表當(dāng)系統(tǒng)時(shí)間走到某分鐘05秒時(shí)觸發(fā)。

    每分鐘0秒觸發(fā)格式為 0 * * * * ? 或者 0 0/1 * * * ? 。

    最后的問(wèn)號(hào)代表什么:

    其實(shí)最后一位代表星期幾。為避免與前面沖突,故使用 ? 來(lái)表示任意。

  • 八. SpringBootAdmin監(jiān)控

  • 簡(jiǎn)介:

    分布式監(jiān)控程序,非 SpringBoot官方開(kāi)發(fā),使用時(shí)需導(dǎo)入與之對(duì)應(yīng)的官方版本號(hào),否則報(bào)錯(cuò)。

  • 注意事項(xiàng):

    子節(jié)點(diǎn)要開(kāi)放什么內(nèi)容全部由子節(jié)點(diǎn)規(guī)定,Server無(wú)權(quán)干涉。(安全性)

  • 實(shí)現(xiàn)流程:

    • 導(dǎo)包 admin + SpringBoot Web

    • yml配置主從客戶端

      配置Server,主程序上開(kāi)啟 @EnableAdminServer注解, yml中配置端口。

      配置Client,yml中配置主服務(wù)器即可。

  • 簡(jiǎn)單實(shí)現(xiàn)

    配置 Server:

  • 創(chuàng)建 SpringBoot程序時(shí)選擇 ops中的 Server與 SpringBoot Web項(xiàng)目
  • 配置 yml端口,這里我設(shè)置為80
  • 主程序上配置開(kāi)啟Server
  • server: port: 80 @EnableAdminServer

    配置 Client:

  • 創(chuàng)建SpringBoot程序時(shí)選擇 ops中的Server與 SpringBoot Web項(xiàng)目(此處勾選 web純粹是為了能使 SpringBoot項(xiàng)目持續(xù)運(yùn)行,實(shí)際生產(chǎn)中可以勾選別的,達(dá)到效果就可以)
  • 配置 yml:Server地址、開(kāi)放的數(shù)據(jù)內(nèi)容等
  • server:port: 8080spring:boot:admin:client:url: http://localhost #server路徑地址 management:endpoints:web:exposure:include: "*" #開(kāi)放所有,即13個(gè)端點(diǎn)endpoint:health:show-details: always #展示細(xì)節(jié),true。默認(rèn)false
  • 界面預(yù)覽

    打開(kāi) Server主頁(yè)地址,可以看到許多的數(shù)據(jù)

  • info信息配置

    • info端點(diǎn):在 Server中展示 client業(yè)務(wù)信息的端點(diǎn),比如程序名、作者,初始值為空。
    # yml文件中添加以下配置 management:info:env:enabled: true #使能夠info info:author: ThinkStudes: "good program" #具體信息,純手工編寫(xiě)yml
    • 上述配置的另一種實(shí)現(xiàn)方案:創(chuàng)建 Bean并繼承 InfoContributor 后編寫(xiě)配置。
    @Component public class AppinfoContributor implements InfoContributor {@Overridepublic void contribute(Info.Builder builder) {builder.withDetail("msg","good");} }
  • 自定義Health健康狀況

    ? 比如 client程序中存在 Redis,那么就會(huì)顯示redis的健康狀況。

    四種狀態(tài):

    ? up在線、down離線、unkown未知、outofservice失去服務(wù)。

    ? 我們可以利用四種狀態(tài)在編碼中寫(xiě)一些自定義程序,然后為這些程序添加 health監(jiān)控。

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-yX3TLkw1-1651739102964)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1o6xhkv8sj21xs0u0tcc.jpg)]

    @Component public class HealthConfig extends AbstractHealthIndicator {@Overrideprotected void doHealthCheck(Health.Builder builder){boolean check=true;if (check){builder.withDetail("runtime","xxx");builder.status(Status.UP);}else{builder.withDetail("error","系統(tǒng)運(yùn)行失敗");builder.status(Status.DOWN);}} }

  • 結(jié)合郵件系統(tǒng):郵件信息報(bào)警系統(tǒng)

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-MBjnpfJ6-1651739102964)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1o6xhb71xj21cm0man1y.jpg)]

  • 九. 消息中間件

  • 基礎(chǔ)概念:
    • MQ:Message Queue,消息隊(duì)列。
    • JMS:Java Message Service;一個(gè)規(guī)范,等同于JDBC,提供了與消息服務(wù)相關(guān)的API接口
    • AMQP: advanced message queue protocal,高級(jí)消息傳輸協(xié)議,一種協(xié)議,不一定要遵守。其解決了JMS中的數(shù)據(jù)格式不唯一的缺點(diǎn),統(tǒng)一使用byte[ ]。
    • Kafka:大數(shù)據(jù)技術(shù),可以用作消息中間件,但是主要功能不是此。其是一種高吞吐量的分布式發(fā)布訂閱消息系統(tǒng),提供實(shí)時(shí)消息功能。
  • JMS規(guī)范簡(jiǎn)介
    • JMS消息模型

      • Peer-to-peer:P2P,點(diǎn)對(duì)點(diǎn)模型,一對(duì)一。
      • publish-subscribe:發(fā)布訂閱模型,消息可以被多個(gè)消費(fèi)者消費(fèi),生產(chǎn)者與消費(fèi)者完全獨(dú)立,不需要告知對(duì)方自身的存在。
    • JMS消息種類

      TextMessage、MapMessage、ByteMessage、StreamMessage、ObjectMessage、Message

    • 實(shí)現(xiàn)JMS的技術(shù)

      ActiveMQ、Redis、RabbitMQ、RocketMQ(沒(méi)有完全實(shí)現(xiàn))

  • AMQP協(xié)議簡(jiǎn)介
    • 優(yōu)點(diǎn):

      具有跨平臺(tái)性,服務(wù)器、供應(yīng)商、生產(chǎn)者消費(fèi)者可以使用不同的語(yǔ)言來(lái)實(shí)現(xiàn)。

    • AMQP消息模型:

      direct exchange、fanout exchange、topic exchange、headers exchange、system exchange

    • AMQP消息種類:byte[ ]

    • AMQP實(shí)現(xiàn):

      RabbitMQ、RockerMQ、StormMQ等

  • 四種消息中間件簡(jiǎn)介

    ActiveMQ:Apache產(chǎn)品,社區(qū)已經(jīng)不活躍。

    RabbitMQ:使用頻率較高,速度中等,數(shù)據(jù)直接寫(xiě)在磁盤(pán)中,不易丟失。

    RocketMQ:阿里巴巴開(kāi)源的消息中間件,Java語(yǔ)言開(kāi)發(fā),各方面也表現(xiàn)的比較優(yōu)越,幾乎同時(shí)解決了Kafka和RabbitMQ它們兩個(gè)的缺點(diǎn),速度介于兩者之間,數(shù)據(jù)不易丟失。

    Kafka:速度快,但數(shù)據(jù)寫(xiě)在內(nèi)存中、易丟失。

  • 實(shí)現(xiàn)暫略。

  • 十. 自定義錯(cuò)誤頁(yè)

  • 簡(jiǎn)介:

    • Spring Boot 中的錯(cuò)誤默認(rèn)由 BasicErrorController 類來(lái)處理
    • 如果開(kāi)發(fā)者不需要向用戶展示詳細(xì)的錯(cuò)誤信息,那么可以把錯(cuò)誤信息定義成靜態(tài)頁(yè)面
    • 在resources/static 中創(chuàng)建 error目錄,然后導(dǎo)入錯(cuò)誤展示頁(yè)面。
  • 原理:

    ? 當(dāng)觸發(fā)錯(cuò)誤頁(yè)面時(shí),BasicErrorController類被調(diào)用。(其將會(huì)返回 JSON或 html格式的錯(cuò)誤數(shù)據(jù),具體由用戶請(qǐng)求方式而定)

    • JSON格式的 error得到解決,html格式的 error傳到下一步。
    • 觸發(fā) DefaultErrorViewResolver類,開(kāi)始在 error目錄查找 4__ 、5__格式的錯(cuò)誤頁(yè)面。
    • **(還是找不到時(shí)觸發(fā))**回到 errorHtml ( )方法,使用 error 作為默認(rèn)的錯(cuò)誤頁(yè)面視圖名,如果名 error的視圖也找不到,就會(huì)展示默認(rèn)錯(cuò)誤頁(yè)面。
  • 簡(jiǎn)單實(shí)現(xiàn)
  • 獲取錯(cuò)誤的靜態(tài)頁(yè)面,置于 /resource/static/error 目錄中。

    • 兩種形式:

      xx形式 與 具體的數(shù)字形式。4xx.html、5xx.html的優(yōu)先級(jí)低于具體的數(shù)字權(quán)限,如404、503等,所以它們是可以同時(shí)的存在的。

  • 復(fù)雜實(shí)現(xiàn)(自由度很高)
  • @Component public class MyException extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {Map<String ,Object> map=super.getErrorAttributes(webRequest, options);map.remove("error");map.put("msg","錯(cuò)誤請(qǐng)求");return map;} }

    十一. Slf4j日志使用

  • 簡(jiǎn)介:

    • Lombok包中提供的注解。
    • 針對(duì)類使用、打印類的日志。
    • 在開(kāi)發(fā)中,應(yīng)該盡量使用日志而不是打印 Print。
  • 簡(jiǎn)單實(shí)現(xiàn):

    • 注解實(shí)現(xiàn)
    @Slf4j @RestController @RequestMapping("/users") public class UsersController {@GetMapping()String getById(HttpServletResponse response) throws IOException {log.error("fashion");return "啊啊啊啊";} }
    • 原生創(chuàng)建
    Logger log= LoggerFactory.getLogger(UsersController.class);
  • 效果:
  • **從左至右:**日志記錄時(shí)間、級(jí)別、PID、所屬線程、類對(duì)象、信息。

    十二. 靜態(tài)資源訪問(wèn)

  • 簡(jiǎn)介

    • 在SpringMVC 中,對(duì)于所有的靜態(tài)資源都需要開(kāi)發(fā)者手動(dòng)配置資源過(guò)濾
    • Spring Boot簡(jiǎn)化了靜態(tài)資源過(guò)濾配置
    • SpringBoot靜態(tài)資源自動(dòng)化配置類: WebMvcAuto Configuration。
  • 位置說(shuō)明

    SpringBoot默認(rèn)會(huì)過(guò)濾所有的靜態(tài)資源,一共有5個(gè)位置

    開(kāi)發(fā)者可以將靜態(tài)資源放在這5個(gè)位置中的任意一個(gè),優(yōu)先級(jí)依次降低

  • classpath:/META-INF/resource/ classpath:/resource/ classpath:/static/ classpath:/public/ /
  • 沖突說(shuō)明
  • ? 如果將文件夾中存在同名文件,則只有第一個(gè)會(huì)生效。

    十三. 路徑映射

  • 簡(jiǎn)介

    ? 正常情況,如果我們有靜態(tài)網(wǎng)頁(yè)會(huì)放在/static里,然后訪問(wèn)的時(shí)候需要添加 .html后綴。如果不想添加.html后綴,則需要在 Controller中加一層轉(zhuǎn)發(fā)的操作。

    ? 但是我們有更簡(jiǎn)單的方法,而且節(jié)省資源。

  • 效果:

    訪問(wèn) http://localhost/aaa

    相當(dāng)于 http://localhost/aaa.html

  • 簡(jiǎn)單實(shí)現(xiàn):

    首先將文件置于/static下。

  • ? 然后編寫(xiě) @Configuration、配置 WebMvcConfigurer接口,實(shí)現(xiàn)跳轉(zhuǎn)。

    @Configuration public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/uuu").setViewName("/uuu.html");registry.addViewController("/ooo").setViewName("/ooo.html");} }

    十四. 服務(wù)器日志

  • 簡(jiǎn)介:

    在服務(wù)器中使用日志。

    在正式業(yè)務(wù)上線后不能使用開(kāi)發(fā)工具進(jìn)行調(diào)試,我們需要日志系統(tǒng)。

  • 說(shuō)明:

    保存到服務(wù)器上的日志數(shù)據(jù),我們可以使用 IDEA打開(kāi)(擁有格式)。

  • 簡(jiǎn)單使用

  • logging:file:max-history: 10max-size: 10MBname: server.logpattern:rolling-file-name: server.%d{yyyy-MM-dd}.%i.log

    十五. 多環(huán)境開(kāi)發(fā) Profile

  • 簡(jiǎn)介:

    SpringBoot約定在不同環(huán)境下配置文件的名稱規(guī)則為

    • application-{profile} .properties
    • application-{profile}.yml

    profile占位符表示當(dāng)前環(huán)境的名稱。

  • 作用:

    解決在多環(huán)境開(kāi)發(fā)下配置文件混亂的問(wèn)題。

  • 版本限制說(shuō)明:

    • SpringBoot 2.4之include
    • SpringBoot 2.4之group
    • 阿里云現(xiàn)在的是2.3.7版本
  • 簡(jiǎn)單實(shí)現(xiàn)

    • 在主 yml配置文件以外,編寫(xiě)多份 yml文件
      • application-dev
      • application-devDB
      • application-MVC
    • 在主 yml配置文件中選擇性的引入其他配置文件。

    十六. 優(yōu)先執(zhí)行的代碼

  • 簡(jiǎn)介:

    ? 有一些特殊任務(wù)需要在系統(tǒng)啟動(dòng)時(shí)執(zhí)行(例如配置文件加載、數(shù)據(jù)庫(kù)初始化等),SpringBoot對(duì)此提供了兩種基本一樣的方案:CommandLineRunner類、ApplicationRunner類。

  • 兩種簡(jiǎn)單實(shí)現(xiàn):

    ? CommandLineRunner:Spring Boot 項(xiàng)目在啟動(dòng)時(shí)會(huì)遍歷所有 CommandLineRunner的實(shí)現(xiàn)類,并調(diào)用其中的 run 方法,如果整個(gè)系統(tǒng)中有多個(gè) CommandLineRunner 的實(shí)現(xiàn)類,那么可以使用 @Order注解對(duì)這些實(shí)現(xiàn)類的調(diào)用順序進(jìn)行排序。Order值越小越優(yōu)先執(zhí)行,可為負(fù)數(shù),負(fù)數(shù)最小。

  • @Component @Order(-100) public class StartPrint implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("優(yōu)先啟動(dòng)~");} }

    ? ApplicationRunner:幾乎同上。兩者 Order通用,計(jì)算執(zhí)行順序的時(shí)候需要同時(shí)參考兩者。

    @Component @Order(-1000) public class Start03 implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("33333");} }

    十七. 異常處理器

  • 簡(jiǎn)介:

    異常,指的是當(dāng)正常訪問(wèn)時(shí)服務(wù)器時(shí)發(fā)生的異常,并非指 404之類的異常。

  • 簡(jiǎn)單實(shí)現(xiàn)

    ( utils包下的異常處理類)

  • // 攔截所有異常 @RestControllerAdvice public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class)R allException(Exception ex) {ex.printStackTrace();return new R("服務(wù)器發(fā)生未知故障,請(qǐng)稍后重試...");} }

    十八. 配置日志等級(jí)

  • 簡(jiǎn)介:

    在 yml中配置當(dāng)前日志的打印等級(jí),一共有兩種形式。

    • 按包名劃分
    • 按分組劃分
  • 簡(jiǎn)單實(shí)現(xiàn):

  • 按包名劃分

    logging:level:root: error # root是根路徑 / 的正式寫(xiě)法com.test.controller: info

    分組劃分,先分組再劃定等級(jí)。

    logging:group:ebank_name: com.test.controller,com.test.mapperlevel:root: errorebank: info

    十九. 兼容xml配置文件

  • 簡(jiǎn)介:

    ? 有時(shí)候我們需要改寫(xiě)一些比較老的程序,或者作 xml文件配置。

    ? 雖然 SpringBoot不推薦使用 xml進(jìn)行配置,但是如果開(kāi)發(fā)者需要使用 xml配置,那么只需在 resources目錄下提供配置文件、然后在主程序上導(dǎo)入即可。

  • 說(shuō)明:

    • @ImportResource:導(dǎo)入 XML配置文件。
    • @Import:導(dǎo)入其他配置類。
  • [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-yWRboVy5-1651739102965)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1sq40ejyaj214a0aoabn.jpg)]

    二十. 讀取標(biāo)準(zhǔn) yml配置

  • 簡(jiǎn)介:

    ? yml 中編寫(xiě)了眾多屬性,那么該入伙獲取呢?

  • 獲取方式分類:

    • 單個(gè)讀取
    • 全部讀取
    • 選擇讀取
  • 單個(gè)讀取:@Value注解

  • @Value("${users[0].name}") String name;@Value("${a.b.c:10}") // 讀取不到則加載默認(rèn)值 String num;
  • 全部讀取:利用被 Spring封裝的 Enviroment對(duì)象,該對(duì)象中包含了所有的 yml文件屬性。
  • @Autowired Environment env;@Test void contextLoads() {env.getProperty("users[0].name"); }
  • 選擇讀取:既可以為 Spring原生 Bean注入屬性,也可以為第三方 Bean注入屬性。

    實(shí)現(xiàn)步驟:

    • yml存在數(shù)據(jù)

    • 創(chuàng)建屬性獲取 Bean( @Component + @Data + @ConfigurationProperties 注解)。

      在這一步 Spring可能會(huì)提示缺少相應(yīng)包,按提示導(dǎo)入即可。

    • 注入該 Bean并使用

  • @Data @Component @ConfigurationProperties("users2") public class UsersConfiguration {String name;String age; } // 使用 @Autowired UsersConfiguration userConfig;

    二十一. 讀取第三方 yml配置

  • 簡(jiǎn)介:

    ? 我懷疑此種方式存在Bug,單級(jí)可以識(shí)別,一旦遇到多級(jí)就不能識(shí)別我的文件。還應(yīng)該注意的是,方法不止這一種,但這種比較直接。

  • 簡(jiǎn)單實(shí)現(xiàn):

    @PropertySource屬性引入第三方文件(得加上類全路徑名)

  • @Data @Configuration @PropertySource(value = "classpath:users.yml") public class CustomConfig {@Value("${users}")Object name; }

    二十二. 攔截器

    ? 所有的攔截器都必須實(shí)現(xiàn) HandlerInterceptor接口。

    ? **攔截器( Interceptor)**同 Filter 過(guò)濾器一樣,都是面向切面編程 AOP 的具體實(shí)現(xiàn)。

  • 必須實(shí)現(xiàn)的三個(gè)方法。

    • preHandle:控制器方法執(zhí)行之前執(zhí)行 preHandle(),其 boolean類型的返回值表示是否攔截或放行,返回 true為放行,即調(diào)用控制器方法;返回 false表示攔截,即不調(diào)用控制器方法。當(dāng)它返回 false 時(shí),表示請(qǐng)求結(jié)束,
    • postHandle: 方法在當(dāng)前請(qǐng)求處理完成之后,也就是 Controller 方法調(diào)用之后執(zhí)行。但是它會(huì)在 DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用,我們可以在這個(gè)方法中對(duì) Controller 處理之后的 ModelAndView 對(duì)象進(jìn)行操作。
    • afterComplation:該方法在整個(gè)請(qǐng)求結(jié)束之后,也就是在 DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行,主要用來(lái)進(jìn)行資源清理。
    • 執(zhí)行順序:preHandle ----> Controller ----> postHandle ----> afterComplation
  • 多個(gè)攔截器的執(zhí)行順序

    • 攔截器的執(zhí)行順序?yàn)?strong>鏈條。
    • ==注意:==當(dāng)某個(gè)攔截器方法返回值為 false時(shí),后續(xù)的 Interceptor和 Controller都不會(huì)再執(zhí)行,所以一般需要手寫(xiě)為 true。
  • 實(shí)現(xiàn)步驟:

    • 繼承自 HandlerInterceptor,重寫(xiě)方法
    • @Configuration中 注冊(cè)攔截器:將攔截器 Bean交由 SpringMVC攔截器類 WebMvcConfigurer管理。
  • 在這一步才能配置攔截的路徑,還可以配置排除的路徑 excludePathPatterns。

    二十三. 頁(yè)面跳轉(zhuǎn)

    原理:利用 ModelAndView對(duì)象。

    @GetMapping ModelAndView get() {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("/uuu.html");return modelAndView; }

    7?? SpringBoot常用技巧

    一. 獲取UUID的正確姿勢(shì)

    二. 全路徑名

    ? 在 xml或者 yml文件中進(jìn)行配置時(shí),可以使用全路徑名縮寫(xiě)形式:classpath:

    classpath:UserMapper.class # 相當(dāng)于全路徑+UserMapper.class

    三. 頁(yè)面重定向

    ? 簡(jiǎn)單的頁(yè)面重定向,頁(yè)面跳轉(zhuǎn)與重定向并不一樣。

    @GetMapping() String getById(HttpServletResponse response) throws IOException {response.sendRedirect("/cancel.html");return null; }

    四. 表格的畫(huà)法

    我是實(shí)在想不到,竟然還會(huì)有表格畫(huà)法這種教程。

    節(jié)點(diǎn)用+號(hào)碼表示,線條用-號(hào)表示,空格表示表中的待填項(xiàng)。

    System.out.println("+----+--------+"); System.out.println("+ | |"); System.out.println("+ | |"); System.out.println("+----+--------+");

    五. yml中相互引用

    ? dollar + 大括號(hào)

    username: kkyour_name: ${username}

    六. 隨時(shí)獲取 ApplicationContext

  • 為什么能夠?qū)崿F(xiàn)?

    ? 理解 SpringBoot底層工作源碼,采取官方接口 ___Aware。

  • 簡(jiǎn)單實(shí)現(xiàn):

    只要繼承 ApplicationContextAware并實(shí)現(xiàn) set方法即可。

    public class Demo01 implements ApplicationContextAware {ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;} }

  • 七. 網(wǎng)站圖標(biāo) favicon

  • 簡(jiǎn)介

    favicon,網(wǎng)站圖標(biāo)。

    雖然在 html代碼中也可以添加,不過(guò)在此添加較為方便。

  • 簡(jiǎn)單實(shí)現(xiàn)

    • 將普通圖片轉(zhuǎn)為 ico圖標(biāo)文件,鏈接
    • 重命名為 favicon.ico ,置于 /resource/static/ 下。
  • 八. 跳過(guò)測(cè)試模塊

  • 問(wèn)題簡(jiǎn)介

    SpringBoot程序在打包的時(shí)候會(huì)默認(rèn)先執(zhí)行測(cè)試類 Test里面的方法。

    這是因?yàn)榇嬖?Maven生命周期,后執(zhí)行的必須先執(zhí)行前面的所有內(nèi)容。

  • 解決:maven設(shè)置跳過(guò)測(cè)試

    九. 排除自動(dòng)配置

  • 簡(jiǎn)介:

    手動(dòng)排除 SpringBoot的自動(dòng)配置。

  • 兩種實(shí)現(xiàn)方法:

    • 主程序上配置

    • yml中配置

    十. 查看 pom組件版本

  • 簡(jiǎn)介:

    查看在 pom文件中導(dǎo)入的具體軟件版本(全部)。

    可以分為兩種,Spring官方 與 阿里云鏡像 所創(chuàng)建的 SpringBoot程序并不一樣。

  • Spring官方

    兩層點(diǎn)擊:spring-boot-starter-parentspring-boot-dependencies

  • 阿里云

    dependencyManagement下的與中,點(diǎn)擊查看。

  • 十一. 正確的項(xiàng)目創(chuàng)建流程

  • 簡(jiǎn)介:

    有利于項(xiàng)目與項(xiàng)目之間的解耦合,促進(jìn)開(kāi)發(fā)。

  • 操作流程:

    • 創(chuàng)建空項(xiàng)目工程
    • 在空的項(xiàng)目工程中 添加 所需要的其他組件 module。
  • 十二. 離線創(chuàng)建SpringBoot程序

  • 簡(jiǎn)介:

    在沒(méi)有網(wǎng)絡(luò)的計(jì)算機(jī)上創(chuàng)建 SpringBoot程序,過(guò)程離線。

    但事先需要在官網(wǎng)上把相應(yīng)文件創(chuàng)建并下載。

  • 步驟:

    • 官網(wǎng)創(chuàng)建、下載
    • 將項(xiàng)目導(dǎo)入離線設(shè)備
  • 十三. 快速制作程序模板

  • 簡(jiǎn)介:

    制作模板程序,可以在學(xué)習(xí)的過(guò)程中大量復(fù)制某份程序。

  • 制作模板步驟:

    • 選擇模板

    • 刪除項(xiàng)目結(jié)構(gòu)的無(wú)用文件

    • 刪除pom文件兩行、一行(結(jié)束)

      [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-bh5Q4N9S-1651739102967)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1p9wf9t2xj2144092q53.jpg)]

    使用步驟:

    通常都是在項(xiàng)目中直接將上面的模板當(dāng)成組件module導(dǎo)入。

    • 再?gòu)?fù)制出一份模板。
    • 在pom文件中把改成新組件名。
    • IDEA中導(dǎo)入,注意此次選擇的是import module而不是new module
    • 設(shè)置使用的JDK版本。(結(jié)束)

    十四. Tomcat替換成Jetty

  • 簡(jiǎn)介:

    排除 Tomcat依賴,可以換成其他任意服務(wù)器程序。

  • 步驟:

    • pom中排除 Tomcat依賴
    • pom中新增 Jetty依賴
  • <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions> </dependency> <!-------------分割線--------------> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId> </dependency>

    十五. 修改Banner

  • 簡(jiǎn)介:

    修改控制臺(tái)打印出來(lái)的 Banner廣告位。

  • 兩種方法:

    • 純文字:/resource 中編寫(xiě) banner.txt文件,Banner在線生成網(wǎng)站

    • 文字或者圖片:yml中配置

  • #關(guān)閉banner spring:main:banner-mode: off#修改banner為指定圖片 spring:banner:image:location: WechatIMG96.jpeg

    十六. 測(cè)試中開(kāi)啟服務(wù)器配置

  • 簡(jiǎn)介:

    ? 我們?cè)趫?zhí)行測(cè)試的時(shí)候,SpringBoot默認(rèn)不開(kāi)啟服務(wù)器、節(jié)省資源。但是現(xiàn)在由于業(yè)務(wù)需求,需要對(duì)其測(cè)試,采用 WebEnvironment Web環(huán)境。

  • @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class Test03 {@Testvoid test03(){} }

    webEnviroment參數(shù)說(shuō)明:

  • SpringBootTest.WebEnvironment.NONE:默認(rèn)值,不啟動(dòng)服務(wù)器
  • SpringBootTest.WebEnvironment.DEFINED_PORT:使用定義的端口
  • SpringBootTest.WebEnvironment.RANDOM_PORT:使用隨機(jī)的端口
  • SpringBootTest.WebEnvironment.MOCK:欺騙idea
  • 十七. 測(cè)試中開(kāi)啟事務(wù)

  • 簡(jiǎn)介:

    ? 在測(cè)試中經(jīng)常會(huì)有寫(xiě)入數(shù)據(jù)庫(kù)操作,但我只想知道是否執(zhí)行成功,不想污染數(shù)據(jù)庫(kù)。

  • 步驟:

    • SpringBoot程序中已經(jīng)導(dǎo)入 mysql + mybatis的包,沒(méi)有則無(wú)法開(kāi)啟事務(wù)
    • 開(kāi)啟 @Transational 注解
  • @SpringBootTest @Transactional public class Test04 {@Testvoid test04(){} }

    十八. 測(cè)試中的臨時(shí)屬性

  • 簡(jiǎn)介:

    ? 想要在測(cè)試用例中添加一些臨時(shí)屬性,在 @SpringBootTest 中使用參數(shù)屬性注入即可。

  • @SpringBootTest(properties = {"a=b","server.port=99999"}) public class Test02 {@Value("${a}")String msg1;@Value("${server.port}")String msg2;@Testvoid test02( ){System.out.println(msg1);System.out.println(msg2);} }

    十九. @JsonIgnore

  • 簡(jiǎn)介:

    ? 使用 Jackson作為項(xiàng)目的序列化工具時(shí),可以作用在屬性、方法或者類上面,用來(lái)規(guī)避不想要的序列化功能。

  • @JsonIgnore private String username;

    二十. 項(xiàng)目打包構(gòu)建

  • 簡(jiǎn)介:

    ? 我們?cè)?SpringBoot項(xiàng)目中能夠打包是因?yàn)榕渲昧?maven插件,該插件由 SpringBoot parent 中提供。但是其他公司可能不采用 SpringBoot parent 作為parent,此時(shí)就需要配置。

  • 示意圖:避免重復(fù)打包

  • 二十一. IDEA隱藏文件

  • 簡(jiǎn)介:

    隱藏不想看見(jiàn)的文件,避免冗余。

    set up — Edit — File Type.

  • 注意事項(xiàng)

    在 IDEA 2022.01版本中,我遭遇了隱藏文件時(shí)產(chǎn)生的 Bug,需注意。

  • 二十二. jdk8單位類

  • 簡(jiǎn)介:

    ? JDK8 提供了兩個(gè)單位類,用來(lái)規(guī)范單位的表達(dá)形式。

    分別為:

    • 時(shí)間單位:Duration
    • 容量大小單位:DataSize
  • //使用 1. Duration duration1=Duration.of(3, ChronoUnit.HOURS); 2. Duration duration2=Duration.ofHours(3);3. @DurationUnit(ChronoUnit.HOURS)Duration duration3;//DataSize同理,例如: DataSize dataSize=DataSize.ofGigabytes(2);

    8?? SpringBoot不常用操作

    1. 修改配置文件名

    修改配置文件名,然后在程序運(yùn)行時(shí)再指定配置文件名

    雖然感覺(jué)這種方式比較愚蠢,但是暫時(shí)收錄

    2. maven控制yml環(huán)境

    maven是比 Spring更底層的存在,Spring建立在 maven的基礎(chǔ)之上。

    我們可以使用 maven來(lái)控制并改變 Spring運(yùn)行的時(shí)的 yml文件配置。

    3. JDBC使用

    優(yōu)勢(shì)闡述:

    ? Mybatis之類是基于JDBC開(kāi)發(fā)的,可以說(shuō) jdbc是更加底層的存在。

    ? 安全性與底層效率要較其他框架高,銀行相關(guān)行業(yè)比較熱衷此。

    步驟:

  • 導(dǎo)pom包
  • 自動(dòng)注入,直接使用
  • <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId> </dependency> @Autowired JdbcTemplate jdbcTemplate;

    4. 熱部署

    說(shuō)明:

    • 只能夠在開(kāi)發(fā)環(huán)境中使用,并不是生產(chǎn)環(huán)境,也就是只能在 IDEA中使用
    • 部署比直接運(yùn)行run速度要快,因?yàn)椴渴鹗?restart而不是 reload整個(gè)工程。
    • 消耗的資源很多,不實(shí)用,謹(jǐn)慎開(kāi)啟

    開(kāi)啟流程:到pom包、idea設(shè)置中開(kāi)啟。

    5. 開(kāi)啟 Bean校驗(yàn)

  • 利用validation(接口)與hibernate(實(shí)現(xiàn)類)結(jié)合實(shí)現(xiàn)。
  • **具體功能:**可對(duì)自定義的 Bean在運(yùn)行時(shí)進(jìn)行數(shù)據(jù)的校驗(yàn),比如最大值 max、最小值 min、范圍 range等的校驗(yàn),通過(guò)了才能繼續(xù)編譯。
  • **具體使用:**對(duì)于我,暫時(shí)還未想到。
  • <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version> </dependency><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>8.0.0.Alpha3</version> </dependency>

    6. 代碼中編寫(xiě)測(cè)試

    有時(shí)候我們需要在代碼中編寫(xiě)測(cè)試用例,而不使用 postman這類工具。

  • 簡(jiǎn)單測(cè)試:
  • ? get請(qǐng)求訪問(wèn)頁(yè)面,先開(kāi)啟webEnviroment、AutoConfigureMockMVC,然后注入MOckMVC,最后執(zhí)行操作

  • 后續(xù)放棄。
  • 7. 測(cè)試用例中設(shè)置隨機(jī)數(shù)據(jù)

    只是想在測(cè)試的時(shí)候加載一些隨機(jī)數(shù)據(jù),應(yīng)該把以下內(nèi)容用Profile思想來(lái)編寫(xiě):即多份yml文件。

  • 編寫(xiě)yml數(shù)據(jù),里面是dollar大括號(hào)加上隨機(jī)函數(shù)random
  • testData:name: ${random.uuid}age: ${random.int(6,100)}id: ${random.value} #MD5加密,32位
  • 代碼中配置(注入即可,之前使用過(guò))
  • @Data @Component @ConfigurationProperties( "testdata") public class TestDataConfig {String name;Integer age;String id; }
  • 使用:直接 @Autowired 即可使用

  • 9?? 整合第三方

    此章節(jié)需要日積月累。

    一. 整合Mybatis

  • 導(dǎo)包或者勾選包
  • 配置 yml
  • 編寫(xiě) Mapper接口
  • spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/adult?serverTimezone=UTCusername: rootpassword: "$Now2022" @Mapper public interface UsersMapper {@Select("select * from users where id = #{id}")List<Users> getById(Integer id); } @Autowired UsersMapper mapper;
  • 開(kāi)啟 Mybatis運(yùn)行日志
  • mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    二. 整合MybatisPlus

  • 將Mybatis包換成MybatisPlus包
  • Mapper接口繼承BaseMapper< T >
  • 修改ID自增長(zhǎng)策略,逐漸增長(zhǎng)而不是雪花算法增長(zhǎng)
  • 整合業(yè)務(wù)層 Iservice與 ServiceImpl
  • 開(kāi)啟 Mybatis運(yùn)行日志(非 MybatisPlus功能)
  • @Mapper public interface UsersMapper extends BaseMapper<Users> {@Select("select * from users;")List<Users> getAll(); } public class UsersServiceImpl extends ServiceImpl<UsersMapper,Users> implements UsersService , IService<Users> { } mybatis-plus:global-config:db-config:id-type: autoconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    三. 整合Druid

  • 導(dǎo) pom包
  • Yml配置文件加上一行
  • spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/adult?serverTimezone=UTCusername: rootpassword: "$Now2022"

    🔟 Spring Security

    一門(mén)登錄技術(shù), 學(xué)會(huì)不易。

    一. 簡(jiǎn)介

  • Spring Security是基于內(nèi)存級(jí)別的認(rèn)證,不是數(shù)據(jù)庫(kù)。

  • SpringBoot為 SpringSecurity提供了很好的支持。

  • 導(dǎo)包之后,SpringSecurity為我們提供了一個(gè)默認(rèn)頁(yè)面登錄頁(yè)面(未登錄時(shí)攔截了所有的請(qǐng)求!),默認(rèn)賬號(hào)為user,密碼見(jiàn)控制臺(tái)。如果對(duì)初始的賬號(hào)密碼不滿意,可以在yml中修改。

    spring:security:user:name: adminpassword: adminroles: ADMIN #此處是區(qū)分大小寫(xiě)的,需特別注意
  • 二. 使用步驟

  • 導(dǎo)包

  • yml簡(jiǎn)單配置

  • 代碼中正式配置

    配置說(shuō)明:

    • 訪問(wèn)/admin/** 需要 ADMIN角色權(quán)限

    • 訪問(wèn)/user/ ** 需要 CAT或者 USER角色權(quán)限。

    • 訪問(wèn)其他任意資源都要先登錄。

    • 默認(rèn)登錄頁(yè)面是 /login。

    • permitAll作用于 /login ,表示和登錄相關(guān)的接口都不需要認(rèn)證即可訪問(wèn)。

    • csrf( ).disable( )表示關(guān)閉 csrf,防止服務(wù)器被 csrf攻擊。

      (csrf攻擊:Cross Site Request Forgery,跨站請(qǐng)求偽造。)

  • @Configuration public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").access("hasAnyRole('CAT','USER')").anyRequest().authenticated().and().formLogin().loginProcessingUrl("/login").permitAll().and().csrf().disable();} }
  • Basic認(rèn)證:添加 Basic認(rèn)證能夠讓 Postman可訪問(wèn)。
  • .and().httpBasic()

    三. 自定義登錄頁(yè)面與返回值

  • 簡(jiǎn)介:

    ? 目前為止我們使用的還都是 Spring Security默認(rèn)提供的登錄頁(yè)面。

    ? 在前后端分離的開(kāi)發(fā)中,我們需要自定義登錄頁(yè)面與返回的 JSON格式數(shù)據(jù)

  • 思想:

    • 雖然新登錄地址是/login_new,但是最終的數(shù)據(jù)提交地址還是/login。
    • 對(duì)于傳輸過(guò)程中的參數(shù) usename與 password可以自定義而不必固定。
    • 可以設(shè)置登錄成功、失敗返回的數(shù)據(jù)。
  • 簡(jiǎn)單實(shí)現(xiàn)(配置):

  • .and() .formLogin() .loginPage("/login_page") .loginProcessingUrl("/login") .usernameParameter("name") .passwordParameter("pass") .successHandler((req, resp, auth) -> {Object principal = auth.getPrincipal();System.out.println(principal + "-------principle"); resp.setContentType("application/json;charset=utf-8");PrintWriter writer = resp.getWriter();Map<String, Object> map = new HashMap<>(16);map.put("status", "200");map.put("msg", principal);ObjectMapper om = new ObjectMapper();writer.write(om.writeValueAsString(map));writer.flush();writer.close(); }) .failureHandler((req, resp, exception) -> { resp.setContentType("application/json;charset=utf-8");PrintWriter writer = resp.getWriter();resp.setStatus(401);Map<String, Object> map = new HashMap<>(16);if (exception instanceof LockedException){map.put("msg","賬戶凍結(jié)");}else if (exception instanceof BadCredentialsException){map.put("msg","賬號(hào)密碼錯(cuò)誤,請(qǐng)重新輸入");}else {map.put("msg","登錄失敗");}ObjectMapper om = new ObjectMapper();writer.write(om.writeValueAsString(map));writer.flush();writer.close(); }) .permitAll() .and() .csrf() .disable();

    四. 注銷登錄

  • 簡(jiǎn)介:

    ? 默認(rèn)訪問(wèn) /logout即可注銷。

    ? 但是在這里我遇到問(wèn)題,可能是這種方式已經(jīng)失效。

  • 簡(jiǎn)單實(shí)現(xiàn):
  • .and() .logout() .logoutUrl("/logout") .clearAuthentication(true) .invalidateHttpSession(true) .addLogoutHandler((req, resp, authentication) -> { }) .logoutSuccessHandler((req, resp, authentication) -> {try {resp.sendRedirect("/login_page");} catch (IOException e) {e.printStackTrace();} })

    五. 加鹽 Salt

  • 簡(jiǎn)介:

    ? 所謂加鹽就是一種加密形式,其既可以是隨機(jī)數(shù)、也可以是用戶名。

    ? 加鹽之后原本密碼相同的用戶所生成的最終密碼也不會(huì)相同,可以有效防止跑庫(kù)破解密碼。

  • 傳統(tǒng)加鹽方式:需要在數(shù)據(jù)庫(kù)中記錄用戶的鹽值。

  • Spring Security加鹽

    ? Spring Security提供了多種加鹽方案。

    ? 官方推薦使用BCryptPasswordEncoder,其使用了 BCrypt 強(qiáng)哈希函數(shù),開(kāi)發(fā)者在使用時(shí)可以選擇提供 strength 和 SecureRandom 實(shí)例 ,strengh越大,密鑰的迭代次數(shù)越多,迭代次數(shù)為2的strength次方。(strength 取值在4~31 之間,默認(rèn)為 10)

    @Configuration public class PasswordEncoderConfig {@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder(10);} }
  • 簡(jiǎn)單使用:

    • 寫(xiě) service
    • 注冊(cè)時(shí)將 encrypt傳到數(shù)據(jù)庫(kù)(代碼編寫(xiě))

  • 六. 使用注解進(jìn)行配置

  • 簡(jiǎn)介:

    ? 上面都是使用 Java類來(lái)進(jìn)行Spring Security配置,現(xiàn)在采用注解的形式。

    ? 配置內(nèi)容:訪問(wèn)路徑(或者方法)需要授權(quán)。

  • 使用步驟:

    • 開(kāi)啟注解形式
    • 類或者方法上面使用

  • 七. 持久層存儲(chǔ):數(shù)據(jù)庫(kù)

  • 簡(jiǎn)介:

    ? 將 Spring Security基于內(nèi)存級(jí)別的登錄驗(yàn)證信息存儲(chǔ)到數(shù)據(jù)庫(kù)。

  • 遺憾:暫時(shí)未能成功實(shí)現(xiàn)。

  • 實(shí)現(xiàn)步驟:

    • 創(chuàng)建數(shù)據(jù)庫(kù)對(duì)應(yīng)表:首先得創(chuàng)建三張數(shù)據(jù)庫(kù)用戶表
    • 代碼中實(shí)現(xiàn)注冊(cè)與登錄等相關(guān)業(yè)務(wù)
  • 建表語(yǔ)句范例:

  • drop table if exists user; drop table if exists role; drop table if exists user_role; create table user(id int primary key auto_increment,username varchar(32),password varbinary(255),enabled tinyint(1),locker tinyint(1) );create table role(id int,name varchar(32),nameZh varchar(32) );create table user_role(id int(11),uid int(11),rid int(11) )

    八. 令牌技術(shù):token

  • 簡(jiǎn)介:

    ? 本節(jié)基于 OAuth2框架,該框架的使用與實(shí)現(xiàn)賬號(hào)密碼登錄不沖突。

  • 遺憾:暫時(shí)未能成功實(shí)現(xiàn)。

  • 令牌技術(shù)說(shuō)明:

    ? 令牌技術(shù)的優(yōu)勢(shì)在于可以只授權(quán)部分權(quán)限給第三方,從而避免了密碼直接泄露的可能性。第三方拿著令牌可以訪問(wèn)一些基礎(chǔ)資源,如:頭像、用戶名等。很多第三方也只支持 token而不支持 Cookie(如:微信小程序)。

  • 交互流程(三次):

  • OAuth授權(quán)模式說(shuō)明

    ? OAuth具有多種授權(quán)模式,其各有千秋、按需選擇。

  • 九. WebSocket

  • 簡(jiǎn)介:一種 HTTP即時(shí)通信技術(shù),目前流行。
  • 暫無(wú)。
  • 十. Swagger2

  • 簡(jiǎn)介:

    ? 一種可以將 代碼編寫(xiě) 和 需求文檔編寫(xiě) 融為一體的技術(shù)(暫時(shí)無(wú)該需要)。

  • 簡(jiǎn)單實(shí)現(xiàn)

  • 總結(jié)

    以上是生活随笔為你收集整理的SpringBoot笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。