SpringBoot快速入門

先說一些廢話

雖然我的工作中更多的是與數(shù)據(jù)庫打交道,但是作為一個(gè)Coder,我覺得掌握前后端的Web技術(shù)來說是非常有必要的。

不僅可以幫助我們?cè)诠ぷ髦懈玫睦斫馄渌麔徫慌c你對(duì)接的人他的工作痛點(diǎn),也能在公司需要人手的時(shí)候成為一個(gè)有力的應(yīng)急幫手,比如之前公司的數(shù)據(jù)中臺(tái)我就參與架構(gòu)和部分開發(fā)任務(wù),更重要的是我私下里可以運(yùn)用一些快速框架來搭建一些有意思的網(wǎng)站,比如我的個(gè)人主頁個(gè)人博客都是我自學(xué)javajs所做出來的作品。

所以今天我希望整合一些我以往的經(jīng)驗(yàn)和看過的教程文檔,來寫一篇文章,幫助你在一天之內(nèi)通過這篇文章快速學(xué)習(xí)SpringBoot框架以及各種開發(fā)必備的工具與插件?。?!

MVC

什么是MVC

  1. MVC三層架構(gòu)是指:視圖層 View、服務(wù)層 Service,與持久層 Dao,它們分別完成不同的功能
    • View 層:用于接收用戶提交請(qǐng)求的代碼在這里編寫
    • Service 層:系統(tǒng)的業(yè)務(wù)邏輯主要在這里完成
    • Dao 層:直接操作數(shù)據(jù)庫的代碼在這里編寫
  2. 為了更好的降低各層間的耦合度,在三層架構(gòu)程序設(shè)計(jì)中,采用面向抽象編程,即上層對(duì)下層的調(diào)用,是通過接口實(shí)現(xiàn)的,而下層對(duì)上層的真正服務(wù)提供者,是下層接口的實(shí)現(xiàn)類
  3. 服務(wù)標(biāo)準(zhǔn)(接口)是相同的,服務(wù)提供者(實(shí)現(xiàn)類)可以更換,這就實(shí)現(xiàn)了層間解耦合

MVC 架構(gòu)程序的工作流程

  1. 用戶通過 View 頁面向服務(wù)端提出請(qǐng)求,可以是表單請(qǐng)求、超鏈接請(qǐng)求、AJAX 請(qǐng)求等
  2. 服務(wù)端 Controller 控制器接收到請(qǐng)求后對(duì)請(qǐng)求進(jìn)行解析,找到相應(yīng)的 Model 對(duì)用戶請(qǐng)求進(jìn)行處理
  3. Model 處理后,將處理結(jié)果再交給 Controller
  4. Controller 在接到處理結(jié)果后,根據(jù)處理結(jié)果找到要作為向客戶端發(fā)回的響應(yīng) View 頁面,頁面經(jīng)渲染(數(shù)據(jù)填充)后,再發(fā)送給客戶端

使用xml還是注解

  1. 應(yīng)用的基本配置使用xml,比如數(shù)據(jù)源和資源文件等
  2. 業(yè)務(wù)開發(fā)使用注解,比如service注入bean
  3. 但是xml越來越多導(dǎo)致越來越臃腫,最終發(fā)展到使用完全基于注解開發(fā)

注解

聲明Bean注解

@Component 組件沒有明確規(guī)定其角色,作用在類級(jí)別上聲明當(dāng)前類為一個(gè)業(yè)務(wù)組件,被Spring IOC 容器維護(hù)
@Service 在業(yè)務(wù)邏輯層(Service)類級(jí)別進(jìn)行聲明
@Registory 在數(shù)據(jù)訪問層(Dao)類級(jí)別進(jìn)行聲明
@Controller 在展現(xiàn)層(MVC)使用,標(biāo)注當(dāng)前類為一個(gè)控制器

注入Bean注解

@Autowired 它可以對(duì)類成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作,通過@Autowired的使用來消除set、get方法
@Inject 作用同上,是JSR-330 標(biāo)準(zhǔn)
@Resource 作用同上,是JSR-250 標(biāo)準(zhǔn)
以上三種注解在Set方法或?qū)傩陨下暶鳎话闱闆r下更習(xí)慣聲明在屬性上,代碼簡潔清晰

配置與獲取Bean注解

@Configuration 將當(dāng)前類聲明為一個(gè)配置類,相當(dāng)于一個(gè)xml配置文件
@ComponentScan 自動(dòng)掃描包下標(biāo)注有@Repository @Service @Controller
@Component 注解的類并有Spring IOC 容器進(jìn)行實(shí)例化和維護(hù)
@Bean 作用于方法上,聲明當(dāng)前方法的返回值是一個(gè)Bean對(duì)象,相當(dāng)于xml文件<bean>聲明當(dāng)前方法返回一個(gè)bean對(duì)象
@Value 獲取properties文件指定的key/value

pom.xml

作用是添加坐標(biāo)相關(guān)配置,主要是各種依賴jar包

組合注解和元注解

所謂元注解其實(shí)就是可以注解到別的注解上的注解,被注解的注解稱之為組合注解,組合注解具備元注解的功能,主要的作用是消除重復(fù)注解

自定義注解

個(gè)性化的定義自己所需要的功能并聲明一個(gè)注解,簡化工程,可以參考文章————SPRINGBOOT自定義注解學(xué)習(xí)

常用注解

可以參考文章————SpringBoot常用注解集合詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明

@RestController、@ResponseBody、@RequestBody

  1. 相當(dāng)于@Controller + @ResponseBody兩個(gè)注解的結(jié)合,返回JSON數(shù)據(jù)不需要在方法前面加@ResponseBody注解了,
    但使用@RestController這個(gè)注解,就不能返回jsp、html頁面,視圖解析器無法解析jsp、html頁面v
  2. @ResponseBody表示該方法的返回結(jié)果直接寫入HTTP response body中,一般在異步獲取數(shù)據(jù)時(shí)使用(也就是AJAX),
    在使用@RequestMapping后,返回值通常解析為跳轉(zhuǎn)路徑,但是加上@ResponseBody后返回結(jié)果不會(huì)被解析為跳轉(zhuǎn)路徑,而是直接寫入HTTP response body中,
    比如異步獲取JSON數(shù)據(jù),加上@ResponseBody后,會(huì)直接返回JSON數(shù)據(jù)
  3. @RequestBody將 HTTP 請(qǐng)求正文插入方法中,使用適合的 HttpMessageConverter 將請(qǐng)求體寫入某個(gè)對(duì)象

@MapperScan、@Mapper

  1. @Mapper注解:
    • 作用:在接口類上添加了@Mapper,在編譯之后會(huì)生成相應(yīng)的接口實(shí)現(xiàn)類
    • 添加位置:接口類上面
    • 如果想要每個(gè)接口都要變成實(shí)現(xiàn)類,那么需要在每個(gè)接口類上加上@Mapper注解,比較麻煩,解決這個(gè)問題用@MapperScan注解
  2. @MapperScan注解:
    • 作用:指定要變成實(shí)現(xiàn)類的接口所在的包,然后包下面的所有接口在編譯之后都會(huì)生成相應(yīng)的實(shí)現(xiàn)類
    • 添加位置:是在Springboot啟動(dòng)類上面添加
    • 添加@MapperScan("com.winter.da")注解以后,com.winter.dao包下面的接口類,在編譯之后都會(huì)生成相應(yīng)的實(shí)現(xiàn)類

習(xí)慣大于配置目標(biāo)

Spring Boot 的目標(biāo)是快速運(yùn)行,快速創(chuàng)建web應(yīng)用,并獨(dú)立機(jī)型部署(jar包方式,war包方式),相比于Spring框架是全新重寫的框架

核心配置

修改Banner圖標(biāo)

主要是通過修改/src/main/resources目錄下的banner.txt文件,如果沒有則默認(rèn)使用SpringBoot初始Banner
可以個(gè)性化制作Banner的網(wǎng)站制定相應(yīng)的txt文件

全局配置

默認(rèn)是application.properties或者application.yml
坐標(biāo)依賴都配置在pom.xml中,如果添加了依賴以后標(biāo)紅可以使用Maven -> Reload project即可

入口類依靠組合注解@SpringBootApplication

@SpringBootConfiguration 本身是一個(gè)配置類,啟動(dòng)類啟動(dòng)的時(shí)候會(huì)加載
@EnableAutoConfiguration 組合了@AutoConfigurationPackage&@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage 底層是一個(gè)@Import(AutoConfigurationPackage.Registrar.class),其會(huì)把啟動(dòng)類的包下組合都掃描到Spring容器中
@AutoConfigurationImportSelector 讀取大量的自動(dòng)配置類,完成自動(dòng)配置,其讀取的是classpath下的META-INF/spring.factories下的配置文件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

Profile配置————區(qū)分生產(chǎn)和開發(fā)環(huán)境

通過在application.yml中設(shè)置spring.profiles.active=test/dev/prod來動(dòng)態(tài)切換不同環(huán)境,例如:

# 開發(fā)環(huán)境配置文件
application-dev.yml
server:
  prot: 8098

# 測(cè)試環(huán)境配置文件
application-test.yml
server:
  prot: 8097

# 生產(chǎn)環(huán)境配置文件
application-prod.yml
server:
  prot: 8099

# 主配置文件
application.yml
spring:
  profiles:
    active: dev

日志配置

SpringBoot默認(rèn)使用LogBack日志系統(tǒng),一般主流的日志都是用log4j日志系統(tǒng)

如果重復(fù)啟動(dòng)Spring項(xiàng)目,可能會(huì)有端口占用的報(bào)錯(cuò)

  1. 思路是殺死占用端口的進(jìn)程即可,主要是下面兩個(gè)命令
  2. 使用netstat -aon|findstr "被占用的端口"或者tasklist |findstr "進(jìn)程名稱"查詢到端口的進(jìn)程號(hào)
  3. 使用taskkill /f /t /im "進(jìn)程名稱"或者taskkill /f /t /pid "進(jìn)程PID"殺死進(jìn)程即可

事務(wù)控制

聲明式事務(wù)

可以參考文章————SpringBoot聲明式事務(wù)的簡單運(yùn)用詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明
主要應(yīng)用在新增修改刪除上,應(yīng)用注解即可

全局異常

使用@ControllerAdvice配合@ExceptionHandler

可以參考文章————Springboot系列-@ControllerAdvice使用詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明
此注解其實(shí)是一個(gè)增強(qiáng)的Controller,使用這個(gè)Controller,可實(shí)現(xiàn)三個(gè)方面的功能,因?yàn)檫@是SpringMVC提供的功能,所以可以在springboot中直接使用

  1. 全局異常處理 (@ExceptionHandler)
  2. 全局?jǐn)?shù)據(jù)綁定 (@InitBinder)
  3. 全局?jǐn)?shù)據(jù)預(yù)處理 (@ModelAttribute)
package com.fx67ll.springboot.exceptions;

import com.fx67ll.springboot.po.vo.ResultInfo;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class TestGlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultInfo exceptionHandler(Exception exception) {
        ResultInfo resultInfo = new ResultInfo();
        resultInfo.setCode(978);
        resultInfo.setMsg("全局異常攔截,操作失??!");
//        if (exception instanceof ParamsException) {
//            ParamsException paramsException = (ParamsException) exception;
//            resultInfo.setMsg(paramsException.getMsg());
//            resultInfo.setCode(paramsException.getCode());
//        }
        return resultInfo;
    }
}

數(shù)據(jù)校驗(yàn)

為什么要進(jìn)行后端數(shù)據(jù)校驗(yàn)

數(shù)據(jù)的校驗(yàn)是交互式網(wǎng)站一個(gè)不可或缺的功能,前端的js校驗(yàn)可以涵蓋大部分的校驗(yàn)職責(zé),如用戶名唯一性,生日格式,郵箱格式校驗(yàn)等等常用的校驗(yàn)。
但是一般前端傳來的數(shù)據(jù)是不可信的,前端校驗(yàn)過了,后端也應(yīng)該重新校驗(yàn),因?yàn)椴慌懦脩衾@過瀏覽器直接通過Http工具向后端請(qǐng)求的情況。
所以服務(wù)端的數(shù)據(jù)校驗(yàn)也是必要的,可以防止臟數(shù)據(jù)落到數(shù)據(jù)庫中,如果數(shù)據(jù)庫中出現(xiàn)一個(gè)非法的郵箱格式,也會(huì)讓運(yùn)維人員頭疼不已。

如何進(jìn)行后端數(shù)據(jù)校驗(yàn)

  1. SpringBoot中一般使用Spring Validation來進(jìn)行后端數(shù)據(jù)校驗(yàn),它是對(duì)Hibernate Validation進(jìn)行了二次封裝,
    SpringMVC模塊中添加了自動(dòng)校驗(yàn),并將校驗(yàn)信息封裝進(jìn)了特定的類中
  2. 在使用時(shí)我們只需要引入spring-boot-starter-web依賴即可,該模塊會(huì)自動(dòng)依賴spring-boot-starter-validation

Spring Validation 常用注解

@Null:被注釋的元素必須為null
@NotNull:被注釋的元素不能為null,可以為空字符串
@AssertTrue:被注釋的元素必須為true
@AssertFalse:被注釋的元素必須為false
@Min(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值
@Max(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值
@DecimalMin(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值
@DecimalMax(value):被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值
@Size(max,min):被注釋的元素的大小必須在指定的范圍內(nèi)
@Digits(integer,fraction):被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi)
@Past:被注釋的元素必須是一個(gè)過去的日期
@Future:被注釋的元素必須是一個(gè)將來的日期
@Pattern(value):被注釋的元素必須符合指定的正則表達(dá)式
@Email:被注釋的元素必須是電子郵件地址
@Length:被注釋的字符串的大小必須在指定的范圍內(nèi)
@Range:被注釋的元素必須在合適的范圍內(nèi)
@URL:被注解的元素必須是一個(gè)URL
@NotEmpty:用在集合類上,不能為null,并且長度必須大于0
@NotBlank:只能作用在String上,不能為null,而且調(diào)用trim()后,長度必須大于0

自定義注解

可以參考文章————Spring自定義注解(validation)詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明

示例代碼

  1. /com/fx67ll/springboot/controller/UserController.java在傳參的位置添加@Vaild注解表示這里的參數(shù)需要校驗(yàn),需要注意JSON格式和表單格式傳過來的參數(shù)異常會(huì)有些區(qū)別,需要在后面注意
    // 添加用戶
    @PutMapping("/adduser")
    public ResultInfo saveUser(@RequestBody @Valid User user) {
        ResultInfo resultInfo = new ResultInfo();
        userService.saveUser(user);
        return resultInfo;
    }
    
  2. Bean文件/com/fx67ll/springboot/dao/User.java中私有字段上使用注解來校驗(yàn),不貼所有代碼了,僅貼部分重點(diǎn)代碼
    @NotBlank(message = "用戶名稱不能為空!")
    private String userName;
    
    @NotBlank(message = "用戶密碼不能為空!")
    @Length(min = 6, max = 20, message = "密碼長度最少六位且最多二十位!")
    private String userPwd;
    
  3. 在全局自定義異常攔截中/com/fx67ll/springboot/exceptions/TestGlobalExceptionHandler.java向用戶返回錯(cuò)誤代碼和信息
    package com.fx67ll.springboot.exceptions;
    
    import com.fx67ll.springboot.po.vo.ResultInfo;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class TestGlobalExceptionHandler {
    
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public ResultInfo exceptionHandler(Exception exception) {
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.setCode(978);
            resultInfo.setMsg("全局異常攔截,操作失??!");
            // 全局?jǐn)?shù)據(jù)校驗(yàn),注意!?。∈褂?json 請(qǐng)求體調(diào)用接口,校驗(yàn)異常拋出 MethodArgumentNotValidException
            if (exception instanceof MethodArgumentNotValidException) {
                MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) exception;
                resultInfo.setCode(1023);
                resultInfo.setMsg(methodArgumentNotValidException.getBindingResult().getFieldError().getDefaultMessage());
            }
            return resultInfo;
        }
    }
    

靜態(tài)資源

默認(rèn)配置下,我們可以在resources資源目錄下存放web應(yīng)用靜態(tài)資源文件
自定義靜態(tài)資源路徑,可以通過在spring.resources.static-locations后面追加一個(gè)配置classpath:/你自定義的配置目錄/,例如:

# application.yml
spring:
  resources:
    # 多個(gè)目錄使用逗號(hào)隔開
    static-loaction: classpath:/public/,classpath:/static/,classpath:/fx67ll/

打包和部署

jar包

  1. 一般用于編寫依賴工具包
  2. 打包
    • 在IDEARun/Debug ConfigurationsCommand line配置clean complie package -Dmaven.test.skip=true執(zhí)行打包命令
    • target目錄得到待部署的項(xiàng)目文件
  3. 部署
    • 在dos窗口中,執(zhí)行命令java -jar jar包所在的本地目錄

war包

  1. 在生產(chǎn)環(huán)境中最為常見的部署方式
  2. 修改pom.xml,設(shè)置打包模式為war包
    <groupId>com.fx67ll</groupId>
    <artifactId>springboot-quickstart</artifactId>
    <version>0.1.0</version>
    <!--設(shè)置為war包模式-->
    <packaging>war</packaging>
    
  3. 忽略內(nèi)嵌Tomcat
    <!--設(shè)置為外部已提供,表示忽略-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    
  4. 配置生成的war包名稱
    <build>
    <!--設(shè)置war包名稱-->
        <finalName>fx67ll-springboot-quickstart-test</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
  5. 修改Starter類,添加容器啟動(dòng)加載文件(類似讀取web.xml文件)
    • 這里通過繼承SpringBootServletInitiallizer類并重寫configure方法來實(shí)現(xiàn)
    • 在部署項(xiàng)目的時(shí)候指定外部Tomcat讀取項(xiàng)目入口方法
    @SpringBootApplication
    public class Starter extends SpringBootServletInitializer {
        
        public static void main(String[] args) {
            SpringApplication.run(Starter.class);
        }
        
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(Starter.class);
        }
    }
    
  6. 打包
    • 在IDEARun/Debug ConfigurationsCommand line配置clean complie package -Dmaven.test.skip=true執(zhí)行打包命令
    • target目錄得到待部署的項(xiàng)目文件
  7. 部署并訪問
    • 放置到外部tomcat中,執(zhí)行bin目錄下start腳本即可

熱部署

熱部署,就是在應(yīng)用正在運(yùn)行的時(shí)候升級(jí)軟件,卻不需要重新啟動(dòng)應(yīng)用,主要應(yīng)用在開發(fā)過程中

熱部署原理

  1. spring-boot-devtools是一個(gè)為開發(fā)者服務(wù)的一個(gè)模塊,其中最重要的功能就是自動(dòng)應(yīng)用代碼更改到最新的App上面去,
    原理是在發(fā)現(xiàn)代碼有更改之后,重新啟動(dòng)應(yīng)用,但是速度比手動(dòng)停止后再啟動(dòng)還要更快,更快指的不是節(jié)省出來的手工操作的時(shí)間
  2. 其深層原理是使用了兩個(gè)ClassLoader,一個(gè)Classloader加載那些不會(huì)改變的類(第三方Jar包),另一個(gè)ClassLoader加載會(huì)更改的類,稱為restart ClassLoader
    這樣在有代碼更改的時(shí)候,原來的restart ClassLoader被丟棄,重新創(chuàng)建一個(gè)restart ClassLoader,由于需要加載的類相比較少,所以實(shí)現(xiàn)了較快的重啟時(shí)間,大概在5秒以內(nèi)

devtools原理

  1. devtools會(huì)監(jiān)聽classpath下的文件變動(dòng),并且會(huì)立即重啟應(yīng)用(發(fā)生在保存時(shí)機(jī))注意:因?yàn)槠洳捎玫奶摂M機(jī)機(jī)制,該項(xiàng)重啟是很快的
  2. devtools可以實(shí)現(xiàn)頁面熱部署(即頁面修改后會(huì)立即生效,這個(gè)可以直接在application文件中配置spring.thymeleaf.cache=false來實(shí)現(xiàn) 注意:不同的模板配置不一樣

熱部署主要步驟

  1. pom.xml中添加依賴,同時(shí)添加devtools生效標(biāo)志插件
    <!--熱部署插件devtools-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <!--表示當(dāng)前這個(gè)項(xiàng)目被繼承之后,這個(gè)不向下傳遞-->
        <optional>true</optional>
    </dependency>
    
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <!--在原有的基礎(chǔ)上添加-->
        <configuration>
            <!--如果沒有該配置,熱部署插件devtools不生效-->
            <fork>true</fork>
        </configuration>
    </plugin>
    
  2. 修改application.yml全局配置文件,在application.yml中配置spring.devtools.restart.enable=false,此時(shí)restart類加載器還會(huì)初始化,但不會(huì)監(jiān)視文件更新
    spring:
      # 熱部署配置
      devtools:
        restart:
          enabled: true
          # 設(shè)置重啟的目錄,添加目錄的文件需要restart
          additional-paths: src/main/java
          # 解決項(xiàng)目啟動(dòng)重新編譯后接口報(bào)404的問題
          poll-interval: 3000
          quiet-period: 1000
    
  3. 修改 IDEA 配置
    • 修改了java類之后,IDEA 默認(rèn)是不自動(dòng)編譯的,而spring-boot-devtools又是監(jiān)測(cè)classpath下的文件發(fā)生變化才會(huì)重啟應(yīng)用,所以需要設(shè)置 IDEA 的自動(dòng)編譯
    • 設(shè)置自動(dòng)配置 File -> Settings -> Build -> Complier -> Build Project automatically
    • 修改Register屬性,執(zhí)行快捷鍵ctrl + shift + alt + /,選擇Register,勾上Complier autoMake allow when app running
    • 注意 IDEA 2021.2.3 版本中沒有上面的選項(xiàng),遷移到了File -> Settings -> Tools -> Advanced Settings -> Complier -> Allow auto-make to start......
  4. 配置完需要重啟一下,然后有修改的話項(xiàng)目會(huì)自動(dòng)更新,但是如果是自動(dòng)觸發(fā)的話,會(huì)造成頻繁更新,對(duì)硬件有一定的負(fù)擔(dān),所以可以改成手動(dòng)觸發(fā)模式
    • 點(diǎn)擊右上角 Run/Debug Configurations
    • 選擇下拉 Configuration -> Spring Boot -> Running Application Update Policies -> On 'Update' action
    • 選擇 Update classes and resources
    • 如果有更新可以,使用快捷鍵 Ctrl + F10 重新編譯
  5. 快捷鍵Ctrl + F9,使用熱部署重新啟動(dòng)

單元測(cè)試

依賴

<!--單元測(cè)試-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Service業(yè)務(wù)層————業(yè)務(wù)邏輯方法測(cè)試

需要注意的是:

  1. 如果在和main文件夾平級(jí)的test文件夾下新建了java文件夾,但是無法新建java class文件
  2. 那么就需要右鍵文件夾 Mark Directory as -> Test Sources Root之后,文件夾變綠即可
# 示例代碼
package com.fx67ll.springboot.service;

import com.fx67ll.springboot.Starter;
import com.fx67ll.springboot.po.User;
import com.fx67ll.springboot.query.UserQuery;
import com.fx67ll.springboot.srevice.UserService;
import com.github.pagehelper.PageInfo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * Service業(yè)務(wù)方法測(cè)試
 *
 * Junit中的RunWith注解 表示該類是單元測(cè)試的執(zhí)行類
 * SpringRunner 是 spring-test 提供的測(cè)試執(zhí)行單元類(是Spring單元測(cè)試中SpringJUnit4ClassRunner的新名字)
 * SpringBootTest注解 是執(zhí)行測(cè)試程序的引導(dǎo)類
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
public class TestUserService {

    // 日志的使用
    private Logger logger = LoggerFactory.getLogger(TestUserService.class);

    @Resource
    private UserService userService;

    @Before
    public void before() {
        logger.info("單元測(cè)試開始......");
    }

    @Test
    public void testQueryUserById() {
        logger.info("測(cè)試根據(jù)用戶id查詢......");

        User user = userService.queryUserById(1);
        logger.info("用戶記錄: {}", user.toString());
    }

    @Test
    public void testSelectUserListByParams() {
        logger.info("測(cè)試根據(jù)分頁條件查詢用戶列表......");

        UserQuery userQuery = new UserQuery();
        PageInfo<User> pageInfo = userService.selectUserListByParams(userQuery);
        logger.info(pageInfo.toString());
    }

    @After
    public void after() {
        logger.info("單元測(cè)試結(jié)束......");
    }
}

controller控制層————接口方法測(cè)試

使用MockMVC進(jìn)行測(cè)試

MockMvc是由spring-test包提供,實(shí)現(xiàn)了對(duì)Http請(qǐng)求的模擬,能夠直接使用網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller的調(diào)用,使得測(cè)試速度快、不依賴網(wǎng)絡(luò)環(huán)境。
同時(shí)提供了一套驗(yàn)證的工具,結(jié)果的驗(yàn)證十分方便

什么是Mock

在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,模擬對(duì)象mock object是以可控的方式模擬真實(shí)對(duì)象行為的假對(duì)象。
在編程過程中,通常通過模擬一些輸入數(shù)據(jù),來驗(yàn)證程序是否達(dá)到預(yù)期結(jié)果

接口MockMvcBuilder

提供一個(gè)唯一的build方法,用來構(gòu)造MockMvc。
主要有兩個(gè)實(shí)現(xiàn):StandaloneMockMvcBuilderDefaultMockMvcBuilder,分別對(duì)應(yīng)兩種測(cè)試方式,
即獨(dú)立安裝和集成Web環(huán)境測(cè)試(并不會(huì)集成真正的web環(huán)境,而是通過相應(yīng)的Mock API進(jìn)行模擬測(cè)試,無須啟動(dòng)服務(wù)器)。
MockMvcBuilders提供了對(duì)應(yīng)的創(chuàng)建方法standaloneSetup方法和webAppContextSetup方法,在使用時(shí)直接調(diào)用即可。

# 示例代碼
# PS:雖然提示測(cè)試通過,但是控制臺(tái)一直沒有打印出返回信息的記錄,后期有空看看
package com.fx67ll.springboot.controller;

import com.fx67ll.springboot.Starter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
@AutoConfigureMockMvc
public class TestUserController {

    // 日志的使用
    private Logger logger = LoggerFactory.getLogger(TestUserController.class);

    @Autowired
    private MockMvc mockMvc;

    /**
     * 模擬測(cè)試用戶列表查詢
     * 其實(shí)就在模擬真實(shí)環(huán)境下前端對(duì)后端發(fā)起的請(qǐng)求
     */
    @Test
    public void apiTestSelectUserListByParams() throws Exception {

        logger.info("開始模擬發(fā)送查詢用戶列表的請(qǐng)求......");

        // 構(gòu)建請(qǐng)求
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/user/list")
                .contentType("text/html") // 設(shè)置請(qǐng)求頭信息
                .accept(MediaType.APPLICATION_JSON); // 設(shè)置請(qǐng)求Accept頭信息

        // 發(fā)送請(qǐng)求
        ResultActions perform = mockMvc.perform(requestBuilder);

        // 校驗(yàn)請(qǐng)求結(jié)果
        perform.andExpect(MockMvcResultMatchers.status().isOk());

        // 獲取執(zhí)行完成后返回的結(jié)果
        MvcResult mvcResult = perform.andReturn();

        // 得到執(zhí)行后的響應(yīng)
        MockHttpServletResponse response = mvcResult.getResponse();

        // 打印結(jié)果
        logger.info(String.valueOf(response.getContentLength()));
        logger.info("響應(yīng)狀態(tài): ", response.getStatus());
        logger.info("響應(yīng)信息: ", response.getContentAsString());

        logger.info("結(jié)束模擬發(fā)送查詢用戶列表的請(qǐng)求......");
    }

    @Test
    public void apiTestQueryUserByUsername() throws Exception {

        logger.info("開始模擬根據(jù)用戶名查詢用戶記錄的請(qǐng)求......");

        // 構(gòu)建請(qǐng)求并發(fā)送
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/user/name/admin"))
                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();

        // 打印結(jié)果
        logger.info("響應(yīng)狀態(tài): ", mvcResult.getResponse().getStatus());
        logger.info("響應(yīng)信息: ", mvcResult.getResponse().getContentAsString());

        logger.info("結(jié)束模擬根據(jù)用戶名查詢用戶記錄的請(qǐng)求......");
    }
}

Swagger2文檔工具

依賴

pom.xml中添加以下代碼

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

常用注解

可以參考文章————swagger2 注解說明詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明

@Api

主要是用在請(qǐng)求類上,用于說明該類的作用

# 示例
@Api(tags = "xx模塊")

@ApiOperation

主要是用在請(qǐng)求的方法上,說明方法的作用

# 示例
@ApiOperation(value = "xx方法的作用", notes = "xx方法的備注說明")

@ApiImplicitParams、@ApiImplicitParam

主要是用在請(qǐng)求的方法上,說明方法的參數(shù)

# 詳細(xì)參數(shù)說明
@ApiImplicitParams:用在請(qǐng)求的方法上,包含一組參數(shù)說明
    @ApiImplicitParam:對(duì)單個(gè)參數(shù)的說明      
        name:參數(shù)名
        value:參數(shù)的說明、描述
        required:參數(shù)是否必須必填
        paramType:參數(shù)放在哪個(gè)地方
            · query --> 請(qǐng)求參數(shù)的獲?。篅RequestParam
            · header --> 請(qǐng)求參數(shù)的獲?。篅RequestHeader       
            · path(用于restful接口)--> 請(qǐng)求參數(shù)的獲?。篅PathVariable
            · body(請(qǐng)求體)-->  @RequestBody User user
            · form(普通表單提交)     
        dataType:參數(shù)類型,默認(rèn)String,其它值dataType="Integer"       
        defaultValue:參數(shù)的默認(rèn)值
    
# 單個(gè)參數(shù)示例    
@ApiImplicitParam(name = "xxx", value = "xxx", required = true, paramType = "path", dataType = "String", defaultValue = "")

# 多個(gè)參數(shù)示例
@ApiImplicitParams({
    @ApiImplicitParam(name = "xxxa", value = "xxxa", required = true, paramType = "body", dataType = "String", defaultValue = ""),
    @ApiImplicitParam(name = "xxxb", value = "xxxb", required = true, paramType = "body", dataType = "String", defaultValue = ""),
})

@ApiResponses、@ApiResponse

主要是用在請(qǐng)求的方法上,說明錯(cuò)誤響應(yīng)的信息

# 詳細(xì)參數(shù)說明
@ApiResponses:響應(yīng)狀態(tài)的說明。是個(gè)數(shù)組,可包含多個(gè) @ApiResponse
    @ApiResponse:每個(gè)參數(shù)的說明
        code:數(shù)字,例如400
        message:信息,例如"請(qǐng)求參數(shù)沒填好"
        response:拋出異常的類
    
# 多個(gè)參數(shù)示例,一般響應(yīng)都是多個(gè)code,所以不寫單個(gè)參數(shù)的示例了
@ApiResponses({
        @ApiResponse(code = 200, message = "請(qǐng)求成功"),
        @ApiResponse(code = 578, message = "請(qǐng)求參數(shù)錯(cuò)誤"),
        @ApiResponse(code = 404, message = "請(qǐng)求路徑?jīng)]有或頁面跳轉(zhuǎn)路徑不對(duì)")
})

@ApiModel、@ApiModelProperty

  1. @ApiModel 經(jīng)常用于請(qǐng)求的入?yún)?duì)象和響應(yīng)返回值對(duì)象的描述
    • 入?yún)⑹菍?duì)象,即 @RequestBody 時(shí), 用于封裝請(qǐng)求(包括數(shù)據(jù)的各種校驗(yàn))數(shù)據(jù)
    • 返回值是對(duì)象,即 @ResponseBody 時(shí),用于返回值對(duì)象的描述
  2. @ApiModelProperty 用于每個(gè)屬性上面,說明屬性的含義
# 示例
@ApiModel(description = "用戶實(shí)體類")
public class User {
    @ApiModelProperty(value = "用戶名", required = true, example = "0")
    private Integer id;
    
    @ApiModelProperty(value = "用戶ID", required = true, example = "fx67ll")
    private String userName;
    
    @ApiModelProperty(value = "用戶密碼", required = true, example = "xxxxxxxx")
    private String userPwd;
}

分布式緩存工具Ehcache

什么是Ehcache

EhCache是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、精干等特點(diǎn),是Hibernate中默認(rèn)CacheProvider。
Ehcache是一種廣泛使用的開源Java分布式緩存,主要面向通用緩存,Java EE輕量級(jí)容器。
它具有內(nèi)存和磁盤存儲(chǔ),緩存加載器,緩存擴(kuò)展,緩存異常處理程序,一個(gè)gzip緩存servlet過濾器,支持REST APISOAP API等特點(diǎn)。

SpringCache相關(guān)注解

SpringBoot緩存實(shí)現(xiàn)內(nèi)部使用SpringCache實(shí)現(xiàn)緩存控制,這里集成Ehcache實(shí)際上是對(duì)SpringCache抽象的一種實(shí)現(xiàn)
可以參考文章————Spring Cache 簡介詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明

@EnableCaching

開啟緩存功能,一般放在啟動(dòng)類上

@CacheConfig

當(dāng)我們需要緩存的地方越來越多,你可以使用@CacheConfig(cacheNames = {"cacheName"})注解在Class之上來統(tǒng)一指定value的值,
這時(shí)可省略value,如果你在你的方法依舊寫上了value,那么依然以方法的value值為準(zhǔn)

@Cacheable

根據(jù)方法對(duì)其返回結(jié)果進(jìn)行緩存,下次請(qǐng)求時(shí),如果緩存存在,則直接讀取緩存數(shù)據(jù)返回;如果緩存不存在,則執(zhí)行方法,并把返回的結(jié)果存入緩存中,一般用在查詢方法上
注意value后面要使用ehcache.xml文件中所列的cache.name

# 單個(gè)參數(shù)示例代碼
@Cacheable(value = "fx67llCache", key = "#xxx")

# 多個(gè)參數(shù)示例,采用拼接的方式
@Cacheable(value = "fx67llCache", key = "#xxx.xxx + '-' + #xxx.xxx + '-' + #xxx.xxx")

@CachePut

使用該注解標(biāo)志的方法,每次都會(huì)執(zhí)行,并將結(jié)果存入指定的緩存中。其他方法可以直接從響應(yīng)的緩存中讀取緩存數(shù)據(jù),而不需要再去查詢數(shù)據(jù)庫,一般用在新增方法上

# 示例代碼
@CachePut(value = "fx67llCache", key = "#xxx.xxx")

@CacheEvict

使用該注解標(biāo)志的方法,會(huì)清空指定的緩存,一般用在更新或者刪除方法上

# 示例代碼
@CacheEvict(value = "fx67llCache", key = "#xxx")

@Caching

該注解可以實(shí)現(xiàn)同一個(gè)方法上同時(shí)使用多種注解

Ehcache的使用

  1. pom.xml添加依賴
    <!--Ehcache工具依賴-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>
    
  2. 添加ehcache.xml文件
    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache name="fx67llCache">
        <!--
           diskStore:為緩存路徑,ehcache分為內(nèi)存和磁盤兩級(jí),此屬性定義磁盤的緩存位置。參數(shù)解釋如下:
           user.home – 用戶主目錄
           user.dir  – 用戶當(dāng)前工作目錄
           java.io.tmpdir – 默認(rèn)臨時(shí)文件路徑
         -->
        <diskStore path="D:\Java\test-ehcache-cache"/>
    
        <!--
           defaultCache:默認(rèn)緩存策略,當(dāng)ehcache找不到定義的緩存時(shí),則使用這個(gè)緩存策略。只能定義一個(gè)。
         -->
    
        <!--
          name:緩存名稱。
          maxElementsInMemory:緩存最大數(shù)目
          maxElementsOnDisk:硬盤最大緩存?zhèn)€數(shù)。
          eternal:對(duì)象是否永久有效,一但設(shè)置了,timeout將不起作用。
          overflowToDisk:是否保存到磁盤,當(dāng)系統(tǒng)當(dāng)機(jī)時(shí)
          timeToIdleSeconds:設(shè)置對(duì)象在失效前的允許閑置時(shí)間(單位:秒)。僅當(dāng)eternal=false對(duì)象不是永久有效時(shí)使用,可選屬性,默認(rèn)值是0,也就是可閑置時(shí)間無窮大。
          timeToLiveSeconds:設(shè)置對(duì)象在失效前允許存活時(shí)間(單位:秒)。最大時(shí)間介于創(chuàng)建時(shí)間和失效時(shí)間之間。僅當(dāng)eternal=false對(duì)象不是永久有效時(shí)使用,默認(rèn)是0.,也就是對(duì)象存活時(shí)間無窮大。
          diskPersistent:是否緩存虛擬機(jī)重啟期數(shù)據(jù) Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
          diskSpoolBufferSizeMB:這個(gè)參數(shù)設(shè)置DiskStore(磁盤緩存)的緩存區(qū)大小。默認(rèn)是30MB。每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū)。
          diskExpiryThreadIntervalSeconds:磁盤失效線程運(yùn)行時(shí)間間隔,默認(rèn)是120秒。
          memoryStoreEvictionPolicy:當(dāng)達(dá)到maxElementsInMemory限制時(shí),Ehcache將會(huì)根據(jù)指定的策略去清理內(nèi)存。默認(rèn)策略是LRU(最近最少使用)。你可以設(shè)置為FIFO(先進(jìn)先出)或是LFU(較少使用)。
          clearOnFlush:內(nèi)存數(shù)量最大時(shí)是否清除。
          memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,默認(rèn)策略)、FIFO(先進(jìn)先出)、LFU(最少訪問次數(shù))。
               FIFO,first in first out,這個(gè)是大家最熟的,先進(jìn)先出。
               LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點(diǎn)就是講一直以來最少被使用的。如上面所講,緩存的元素有一個(gè)hit屬性,hit值最小的將會(huì)被清出緩存。
               LRU,Least Recently Used,最近最少使用的,緩存的元素有一個(gè)時(shí)間戳,當(dāng)緩存容量滿了,而又需要騰出地方來緩存新的元素的時(shí)候,那么現(xiàn)有緩存元素中時(shí)間戳離當(dāng)前時(shí)間最遠(yuǎn)的元素將被清出緩存。
       -->
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                maxElementsOnDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"/>
    
        <cache
                name="fx67llCache"
                eternal="false"
                maxElementsInMemory="100"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="0"
                timeToLiveSeconds="300"
                memoryStoreEvictionPolicy="LRU"/>
    
    </ehcache>
    
  3. application.yml添加緩存配置
    # Ehcache 緩存配置
    cache:
      ehcache:
        config: classpath:ehcache.xml
    
  4. 在入口類添加@EnableCaching注解,表示開啟緩存
  5. Java Bean 對(duì)象實(shí)現(xiàn)序列化,public class User implements Serializable
  6. 在需要使用的地方使用現(xiàn)關(guān)注解,實(shí)現(xiàn)緩存可以減少從數(shù)據(jù)庫查詢的次數(shù)

定時(shí)調(diào)度工具Quartz

可以參考文章————Quartz定時(shí)調(diào)度詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說明

什么是Quartz

在日常項(xiàng)目運(yùn)行中,我們總會(huì)有需求在某一時(shí)間段周期性的執(zhí)行某個(gè)動(dòng)作,比如每天在某個(gè)時(shí)間段導(dǎo)出報(bào)表,或者每隔多久統(tǒng)計(jì)一次現(xiàn)在在線的用戶量等。
在SpringBoot中有Java自帶的java.util.Timer類,也可以在啟動(dòng)類添加@EnableScheduling注解引入定時(shí)任務(wù)環(huán)境

Quartz的使用

  1. pom.xml添加依賴
    <!--Quartz工具依賴-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    
  2. 添加job包并編寫job任務(wù),實(shí)現(xiàn)job接口,并在execute方法中實(shí)現(xiàn)自己的業(yè)務(wù)邏輯
    package com.fx67ll.springboot.jobs;
    
    import org.quartz.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class TestQuartzJob implements Job {
    
        private Logger logger = LoggerFactory.getLogger(TestQuartzJob.class);
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
            // 獲取整理好的日期時(shí)間
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // 查詢觸發(fā)器名稱和觸發(fā)器屬于哪個(gè)分組
            TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
    
            //打印日志
            logger.info("當(dāng)前觸發(fā)器是: " + triggerKey.getName() + ",它所屬的組別是: " + triggerKey.getGroup() +
                    "----------觸發(fā)時(shí)間: " + simpleDateFormat.format(new Date()) +
                    "-->" + "Hello fx67ll Spring Boot Quartz......");
        }
    }
    
  3. 構(gòu)建調(diào)度配置類,創(chuàng)建JobDetail實(shí)例并定義Trigger注冊(cè)到scheduler,啟動(dòng)scheduler開啟調(diào)度
    package com.fx67ll.springboot.conf;
    
    import com.fx67ll.springboot.jobs.TestQuartzJob;
    import org.quartz.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class QuartzCOnf {
        @Bean
        /**
         * 具體的可以被執(zhí)行的調(diào)度程序
         */
        public JobDetail jobDetailTestQuartz(){
            return JobBuilder.newJob(TestQuartzJob.class).storeDurably().build();
        }
    
        @Bean
        /**
         * 第一個(gè)測(cè)試觸發(fā)器,主要是配置參數(shù)提示什么時(shí)候調(diào)用
         * 應(yīng)用場景有比如定時(shí)發(fā)送郵件之類的
         */
        public Trigger triggerTestQuartzFirst(){
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    // 每五秒執(zhí)行一次
                    .withIntervalInSeconds(1)
                    // 永久重復(fù),一直執(zhí)行下去
                    .repeatForever();
            return TriggerBuilder.newTrigger()
                    // 設(shè)置觸發(fā)器名稱和分組
                    .withIdentity("triggerTestQuartzFirst","groupTestQuartz")
                    .withSchedule(simpleScheduleBuilder)
                    .forJob(jobDetailTestQuartz())
                    .build();
        }
    
        @Bean
        /**
         * 第二個(gè)測(cè)試觸發(fā)器
         */
        public Trigger triggerTestQuartzSecond(){
            return TriggerBuilder.newTrigger()
                    // 設(shè)置觸發(fā)器名稱和分組
                    .withIdentity("triggerTestQuartzSecond","groupTestQuartz")
                    // 這里是通過定義表達(dá)式來表示每5秒執(zhí)行一次,后續(xù)再深入研究下
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                    .forJob(jobDetailTestQuartz())
                    .build();
        }
    }
    

附錄

操作代碼目錄說明

springboot-quickstart springboot-mybatis springboot-mybatis-crud springboot-mybatis-crud-prod
快速入門 整合mybatis 整套crud操作 生產(chǎn)環(huán)境開發(fā)

操作代碼資源地址

  1. springboot-quickstart
  2. springboot-mybatis
  3. springboot-mybatis-crud
  4. springboot-mybatis-crud-prod

參考資料

  1. 參考教程 ———— 兩天搞定SpringBoot框架
  2. 參考文檔 ———— JavaSpringBoot 中 @Autowired用法
  3. 參考文檔 ———— SpringBoot - @Configuration、@Bean注解的使用詳解(配置類的實(shí)現(xiàn))
  4. 參考文檔 ———— 【Spring Boot】Spring基礎(chǔ) —— 組合注解與元注解
  5. 參考文檔 ———— @RestController 和 @Controller 的區(qū)別
  6. 參考文檔 ———— MapperScan注解詳解
  7. 參考文檔 ———— Mapper.xml詳解
  8. 參考文檔 ———— MVC三層架構(gòu)(詳解)
  9. 參考文檔 ———— 配置devtools熱部署
  10. 參考文檔 ———— (十三)SpringBoot2.0熱部署Devtools原理
  11. 參考文檔 ———— 2021版IDEA沒有compiler.automake.allow.when.app.running
  12. 參考文檔 ———— SpringBoot基礎(chǔ)之MockMvc單元測(cè)試
  13. 參考文檔 ———— Ehcache詳細(xì)解讀
  14. 參考文檔 ———— spring boot接入ehcache
  15. 參考文檔 ———— SpringBoot(十二): validation常用注解
  16. 參考文檔 ———— SpringBoot之——Validator校驗(yàn)相關(guān)的注解
  17. 參考文檔 ———— 強(qiáng)悍的Spring之spring validation
  18. json格式校驗(yàn)并顯示錯(cuò)誤_使用 Spring Validation 優(yōu)雅地進(jìn)行參數(shù)校驗(yàn)

我是 fx67ll.com,如果您發(fā)現(xiàn)本文有什么錯(cuò)誤,歡迎在評(píng)論區(qū)討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點(diǎn)一顆Star,Thanks~ :)
轉(zhuǎn)發(fā)請(qǐng)注明參考文章地址,非常感謝?。?!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容