SpringBoot快速入門

先說(shuō)一些廢話

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

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

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

MVC

什么是MVC

  1. MVC三層架構(gòu)是指:視圖層 View贸诚、服務(wù)層 Service方庭,與持久層 Dao,它們分別完成不同的功能
    • View 層:用于接收用戶提交請(qǐng)求的代碼在這里編寫
    • Service 層:系統(tǒng)的業(yè)務(wù)邏輯主要在這里完成
    • Dao 層:直接操作數(shù)據(jù)庫(kù)的代碼在這里編寫
  2. 為了更好的降低各層間的耦合度酱固,在三層架構(gòu)程序設(shè)計(jì)中械念,采用面向抽象編程,即上層對(duì)下層的調(diào)用运悲,是通過(guò)接口實(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. 用戶通過(guò) View 頁(yè)面向服務(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 頁(yè)面,頁(yè)面經(jīng)渲染(數(shù)據(jù)填充)后诊霹,再發(fā)送給客戶端

使用xml還是注解

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

注解

聲明Bean注解

@Component 組件沒(méi)有明確規(guī)定其角色伴箩,作用在類級(jí)別上聲明當(dāng)前類為一個(gè)業(yè)務(wù)組件,被Spring IOC 容器維護(hù)
@Service 在業(yè)務(wù)邏輯層(Service)類級(jí)別進(jìn)行聲明
@Registory 在數(shù)據(jù)訪問(wèn)層(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)裝配的工作,通過(guò)@Autowired的使用來(lái)消除set呵恢、get方法
@Inject 作用同上,是JSR-330 標(biāo)準(zhǔn)
@Resource 作用同上媚创,是JSR-250 標(biāo)準(zhǔn)
以上三種注解在Set方法或?qū)傩陨下暶魃ぃ话闱闆r下更習(xí)慣聲明在屬性上,代碼簡(jiǎn)潔清晰

配置與獲取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è)注解鲸湃,簡(jiǎn)化工程,可以參考文章————SPRINGBOOT自定義注解學(xué)習(xí)

常用注解

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

@RestController暗挑、@ResponseBody、@RequestBody

  1. 相當(dāng)于@Controller + @ResponseBody兩個(gè)注解的結(jié)合斜友,返回JSON數(shù)據(jù)不需要在方法前面加@ResponseBody注解了炸裆,
    但使用@RestController這個(gè)注解,就不能返回jsp鲜屏、html頁(yè)面烹看,視圖解析器無(wú)法解析jsp、html頁(yè)面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è)問(wèn)題用@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)

主要是通過(guò)修改/src/main/resources目錄下的banner.txt文件,如果沒(méi)有則默認(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)和開(kāi)發(fā)環(huán)境

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

# 開(kāi)發(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ù)的簡(jiǎn)單運(yùn)用詳細(xì)學(xué)習(xí)鹰祸,這里后期會(huì)補(bǔ)上說(shuō)明
主要應(yīng)用在新增修改刪除上汽纤,應(yīng)用注解即可

全局異常

使用@ControllerAdvice配合@ExceptionHandler

可以參考文章————Springboot系列-@ControllerAdvice使用詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說(shuō)明
此注解其實(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)。
但是一般前端傳來(lái)的數(shù)據(jù)是不可信的滚朵,前端校驗(yàn)過(guò)了冤灾,后端也應(yīng)該重新校驗(yàn),因?yàn)椴慌懦脩衾@過(guò)瀏覽器直接通過(guò)Http工具向后端請(qǐng)求的情況辕近。
所以服務(wù)端的數(shù)據(jù)校驗(yàn)也是必要的韵吨,可以防止臟數(shù)據(jù)落到數(shù)據(jù)庫(kù)中,如果數(shù)據(jù)庫(kù)中出現(xiàn)一個(gè)非法的郵箱格式移宅,也會(huì)讓運(yùn)維人員頭疼不已归粉。

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

  1. SpringBoot中一般使用Spring Validation來(lái)進(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è)過(guò)去的日期
@Future:被注釋的元素必須是一個(gè)將來(lái)的日期
@Pattern(value):被注釋的元素必須符合指定的正則表達(dá)式
@Email:被注釋的元素必須是電子郵件地址
@Length:被注釋的字符串的大小必須在指定的范圍內(nèi)
@Range:被注釋的元素必須在合適的范圍內(nèi)
@URL:被注解的元素必須是一個(gè)URL
@NotEmpty:用在集合類上顾复,不能為null班挖,并且長(zhǎng)度必須大于0
@NotBlank:只能作用在String上,不能為null芯砸,而且調(diào)用trim()后萧芙,長(zhǎng)度必須大于0

自定義注解

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

示例代碼

  1. /com/fx67ll/springboot/controller/UserController.java在傳參的位置添加@Vaild注解表示這里的參數(shù)需要校驗(yàn)假丧,需要注意JSON格式和表單格式傳過(guò)來(lái)的參數(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中私有字段上使用注解來(lái)校驗(yàn),不貼所有代碼了包帚,僅貼部分重點(diǎn)代碼
    @NotBlank(message = "用戶名稱不能為空渔期!")
    private String userName;
    
    @NotBlank(message = "用戶密碼不能為空!")
    @Length(min = 6, max = 20, message = "密碼長(zhǎng)度最少六位且最多二十位渴邦!")
    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)信峻,注意!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)資源路徑踢步,可以通過(guò)在spring.resources.static-locations后面追加一個(gè)配置classpath:/你自定義的配置目錄/,例如:

# application.yml
spring:
  resources:
    # 多個(gè)目錄使用逗號(hào)隔開(kāi)
    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)境中最為常見(jià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文件)
    • 這里通過(guò)繼承SpringBootServletInitiallizer類并重寫configure方法來(lái)實(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. 部署并訪問(wèn)
    • 放置到外部tomcat中,執(zhí)行bin目錄下start腳本即可

熱部署

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

熱部署原理

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

devtools原理

  1. devtools會(huì)監(jiān)聽(tīng)classpath下的文件變動(dòng),并且會(huì)立即重啟應(yīng)用(發(fā)生在保存時(shí)機(jī))注意:因?yàn)槠洳捎玫奶摂M機(jī)機(jī)制饭入,該項(xiàng)重啟是很快的
  2. devtools可以實(shí)現(xiàn)頁(yè)面熱部署(即頁(yè)面修改后會(huì)立即生效嵌器,這個(gè)可以直接在application文件中配置spring.thymeleaf.cache=false來(lái)實(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>
            <!--如果沒(méi)有該配置爽航,熱部署插件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的問(wèn)題
          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 版本中沒(méi)有上面的選項(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文件夾萝风,但是無(wú)法新建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è)試開(kāi)始......");
    }

    @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ù)分頁(yè)條件查詢用戶列表......");

        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ì)象。
在編程過(guò)程中诅愚,通常通過(guò)模擬一些輸入數(shù)據(jù)寒锚,來(lái)驗(yàn)證程序是否達(dá)到預(yù)期結(jié)果

接口MockMvcBuilder

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

# 示例代碼
# PS:雖然提示測(cè)試通過(guò)衅鹿,但是控制臺(tái)一直沒(mé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("開(kāi)始模擬發(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("開(kāi)始模擬根據(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 注解說(shuō)明詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說(shuō)明

@Api

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

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

@ApiOperation

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

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

@ApiImplicitParams、@ApiImplicitParam

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

# 詳細(xì)參數(shù)說(shuō)明
@ApiImplicitParams:用在請(qǐng)求的方法上耕捞,包含一組參數(shù)說(shuō)明
    @ApiImplicitParam:對(duì)單個(gè)參數(shù)的說(shuō)明      
        name:參數(shù)名
        value:參數(shù)的說(shuō)明、描述
        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)求的方法上,說(shuō)明錯(cuò)誤響應(yīng)的信息

# 詳細(xì)參數(shù)說(shuō)明
@ApiResponses:響應(yīng)狀態(tài)的說(shuō)明弛饭。是個(gè)數(shù)組冕末,可包含多個(gè) @ApiResponse
    @ApiResponse:每個(gè)參數(shù)的說(shuō)明
        code:數(shù)字,例如400
        message:信息孩哑,例如"請(qǐng)求參數(shù)沒(méi)填好"
        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)]有或頁(yè)面跳轉(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è)屬性上面,說(shuō)明屬性的含義
# 示例
@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是一種廣泛使用的開(kāi)源Java分布式緩存呆馁,主要面向通用緩存,Java EE輕量級(jí)容器毁兆。
它具有內(nèi)存和磁盤存儲(chǔ)浙滤,緩存加載器,緩存擴(kuò)展气堕,緩存異常處理程序纺腊,一個(gè)gzip緩存servlet過(guò)濾器,支持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 簡(jiǎn)介詳細(xì)學(xué)習(xí),這里后期會(huì)補(bǔ)上說(shuō)明

@EnableCaching

開(kāi)啟緩存功能梅桩,一般放在啟動(dòng)類上

@CacheConfig

當(dāng)我們需要緩存的地方越來(lái)越多壹粟,你可以使用@CacheConfig(cacheNames = {"cacheName"})注解在Class之上來(lái)統(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ù)庫(kù)黑低,一般用在新增方法上

# 示例代碼
@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í)間無(wú)窮大这刷。
          timeToLiveSeconds:設(shè)置對(duì)象在失效前允許存活時(shí)間(單位:秒)。最大時(shí)間介于創(chuàng)建時(shí)間和失效時(shí)間之間娩井。僅當(dāng)eternal=false對(duì)象不是永久有效時(shí)使用暇屋,默認(rèn)是0.,也就是對(duì)象存活時(shí)間無(wú)窮大洞辣。
          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(最少訪問(wèn)次數(shù))子刮。
               FIFO,first in first out窑睁,這個(gè)是大家最熟的挺峡,先進(jìn)先出。
               LFU担钮, Less Frequently Used沙郭,就是上面例子中使用的策略,直白一點(diǎn)就是講一直以來(lái)最少被使用的裳朋。如上面所講病线,緩存的元素有一個(gè)hit屬性,hit值最小的將會(huì)被清出緩存鲤嫡。
               LRU送挑,Least Recently Used,最近最少使用的暖眼,緩存的元素有一個(gè)時(shí)間戳惕耕,當(dāng)緩存容量滿了,而又需要騰出地方來(lái)緩存新的元素的時(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注解,表示開(kāi)啟緩存
  5. Java Bean 對(duì)象實(shí)現(xiàn)序列化栋豫,public class User implements Serializable
  6. 在需要使用的地方使用現(xiàn)關(guān)注解挤安,實(shí)現(xiàn)緩存可以減少?gòu)臄?shù)據(jù)庫(kù)查詢的次數(shù)

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

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

什么是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開(kāi)啟調(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)用場(chǎ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")
                    // 這里是通過(guò)定義表達(dá)式來(lái)表示每5秒執(zhí)行一次,后續(xù)再深入研究下
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                    .forJob(jobDetailTestQuartz())
                    .build();
        }
    }
    

附錄

操作代碼目錄說(shuō)明

springboot-quickstart springboot-mybatis springboot-mybatis-crud springboot-mybatis-crud-prod
快速入門 整合mybatis 整套crud操作 生產(chǎn)環(huán)境開(kāi)發(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沒(méi)有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ū)討論指正猪勇,感謝您的閱讀设褐!
如果您喜歡這篇文章,歡迎訪問(wèn)我的 本文github倉(cāng)庫(kù)地址泣刹,為我點(diǎn)一顆Star助析,Thanks~ :)
轉(zhuǎn)發(fā)請(qǐng)注明參考文章地址,非常感謝R文M饧健!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掀泳,一起剝皮案震驚了整個(gè)濱河市雪隧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌员舵,老刑警劉巖脑沿,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異马僻,居然都是意外死亡庄拇,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門韭邓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)措近,“玉大人,你說(shuō)我怎么就攤上這事女淑〔t郑!?“怎么了?”我有些...
    開(kāi)封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵诗力,是天一觀的道長(zhǎng)凰浮。 經(jīng)常有香客問(wèn)我我抠,道長(zhǎng)苇本,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任菜拓,我火速辦了婚禮瓣窄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纳鼎。我一直安慰自己俺夕,他們只是感情好裳凸,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著劝贸,像睡著了一般姨谷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上映九,一...
    開(kāi)封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天梦湘,我揣著相機(jī)與錄音,去河邊找鬼件甥。 笑死捌议,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的引有。 我是一名探鬼主播瓣颅,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼着倾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼儡毕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碎节,我...
    開(kāi)封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤曾我,失蹤者是張志新(化名)和其女友劉穎守谓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體您单,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斋荞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虐秦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片平酿。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悦陋,靈堂內(nèi)的尸體忽然破棺而出蜈彼,到底是詐尸還是另有隱情,我是刑警寧澤俺驶,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布幸逆,位于F島的核電站,受9級(jí)特大地震影響暮现,放射性物質(zhì)發(fā)生泄漏还绘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一栖袋、第九天 我趴在偏房一處隱蔽的房頂上張望拍顷。 院中可真熱鬧,春花似錦塘幅、人聲如沸昔案。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)踏揣。三九已至庆亡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捞稿,已是汗流浹背身冀。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留括享,地道東北人搂根。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像铃辖,于是被迫代替她去往敵國(guó)和親剩愧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容