先說(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é)java
和js
所做出來(lái)的作品喊式。
所以今天我希望整合一些我以往的經(jīng)驗(yàn)和看過(guò)的教程文檔孵户,來(lái)寫一篇文章,幫助你在一天之內(nèi)通過(guò)這篇文章快速學(xué)習(xí)SpringBoot
框架以及各種開(kāi)發(fā)必備的工具與插件2砹簟Q咏臁!
MVC
什么是MVC
- MVC三層架構(gòu)是指:視圖層 View贸诚、服務(wù)層 Service方庭,與持久層 Dao,它們分別完成不同的功能
- View 層:用于接收用戶提交請(qǐng)求的代碼在這里編寫
- Service 層:系統(tǒng)的業(yè)務(wù)邏輯主要在這里完成
- Dao 層:直接操作數(shù)據(jù)庫(kù)的代碼在這里編寫
- 為了更好的降低各層間的耦合度酱固,在三層架構(gòu)程序設(shè)計(jì)中械念,采用面向抽象編程,即上層對(duì)下層的調(diào)用运悲,是通過(guò)接口實(shí)現(xiàn)的龄减,而下層對(duì)上層的真正服務(wù)提供者,是下層接口的實(shí)現(xiàn)類
- 服務(wù)標(biāo)準(zhǔn)(接口)是相同的班眯,服務(wù)提供者(實(shí)現(xiàn)類)可以更換希停,這就實(shí)現(xiàn)了層間解耦合
MVC 架構(gòu)程序的工作流程
- 用戶通過(guò) View 頁(yè)面向服務(wù)端提出請(qǐng)求,可以是表單請(qǐng)求署隘、超鏈接請(qǐng)求宠能、AJAX 請(qǐng)求等
- 服務(wù)端 Controller 控制器接收到請(qǐng)求后對(duì)請(qǐng)求進(jìn)行解析,找到相應(yīng)的 Model 對(duì)用戶請(qǐng)求進(jìn)行處理
- Model 處理后磁餐,將處理結(jié)果再交給 Controller
- Controller 在接到處理結(jié)果后违崇,根據(jù)處理結(jié)果找到要作為向客戶端發(fā)回的響應(yīng) View 頁(yè)面,頁(yè)面經(jīng)渲染(數(shù)據(jù)填充)后诊霹,再發(fā)送給客戶端
使用xml還是注解
- 應(yīng)用的基本配置使用xml羞延,比如數(shù)據(jù)源和資源文件等
- 業(yè)務(wù)開(kāi)發(fā)使用注解,比如service注入bean
- 但是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
- 相當(dāng)于
@Controller + @ResponseBody
兩個(gè)注解的結(jié)合斜友,返回JSON
數(shù)據(jù)不需要在方法前面加@ResponseBody
注解了炸裆,
但使用@RestController這個(gè)注解,就不能返回jsp鲜屏、html頁(yè)面烹看,視圖解析器無(wú)法解析jsp、html頁(yè)面v -
@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ù) -
@RequestBody
將 HTTP 請(qǐng)求正文插入方法中,使用適合的 HttpMessageConverter 將請(qǐng)求體寫入某個(gè)對(duì)象
@MapperScan霎褐、@Mapper
- @Mapper注解:
- 作用:在接口類上添加了@Mapper址愿,在編譯之后會(huì)生成相應(yīng)的接口實(shí)現(xiàn)類
- 添加位置:接口類上面
- 如果想要每個(gè)接口都要變成實(shí)現(xiàn)類,那么需要在每個(gè)接口類上加上
@Mapper
注解冻璃,比較麻煩响谓,解決這個(gè)問(wèn)題用@MapperScan
注解
- @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ò)
- 思路是殺死占用端口的進(jìn)程即可,主要是下面兩個(gè)命令
- 使用
netstat -aon|findstr "被占用的端口"
或者tasklist |findstr "進(jìn)程名稱"
查詢到端口的進(jìn)程號(hào) - 使用
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中直接使用
- 全局異常處理 (@ExceptionHandler)
- 全局?jǐn)?shù)據(jù)綁定 (@InitBinder)
- 全局?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)
-
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)了特定的類中 - 在使用時(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ō)明
示例代碼
-
/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; }
- 在
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;
- 在全局自定義異常攔截中
/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包
- 一般用于編寫依賴工具包
- 打包
- 在IDEA
Run/Debug Configurations
下Command line
配置clean complie package -Dmaven.test.skip=true
執(zhí)行打包命令 -
target
目錄得到待部署的項(xiàng)目文件
- 在IDEA
- 部署
- 在dos窗口中丑掺,執(zhí)行命令
java -jar jar包所在的本地目錄
- 在dos窗口中丑掺,執(zhí)行命令
war包
- 在生產(chǎn)環(huán)境中最為常見(jiàn)的部署方式
- 修改
pom.xml
贾虽,設(shè)置打包模式為war包<groupId>com.fx67ll</groupId> <artifactId>springboot-quickstart</artifactId> <version>0.1.0</version> <!--設(shè)置為war包模式--> <packaging>war</packaging>
- 忽略內(nèi)嵌Tomcat
<!--設(shè)置為外部已提供,表示忽略--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
- 配置生成的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>
- 修改
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); } }
- 這里通過(guò)繼承
- 打包
- 在IDEA
Run/Debug Configurations
下Command line
配置clean complie package -Dmaven.test.skip=true
執(zhí)行打包命令 -
target
目錄得到待部署的項(xiàng)目文件
- 在IDEA
- 部署并訪問(wèn)
- 放置到外部tomcat中,執(zhí)行bin目錄下start腳本即可
熱部署
熱部署,就是在應(yīng)用正在運(yùn)行的時(shí)候升級(jí)軟件贮缅,卻不需要重新啟動(dòng)應(yīng)用篇梭,主要應(yīng)用在開(kāi)發(fā)過(guò)程中
熱部署原理
-
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í)間 - 其深層原理是使用了兩個(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原理
- devtools會(huì)監(jiān)聽(tīng)classpath下的文件變動(dòng),并且會(huì)立即重啟應(yīng)用(發(fā)生在保存時(shí)機(jī))注意:因?yàn)槠洳捎玫奶摂M機(jī)機(jī)制饭入,該項(xiàng)重啟是很快的
- devtools可以實(shí)現(xiàn)頁(yè)面熱部署(即頁(yè)面修改后會(huì)立即生效嵌器,這個(gè)可以直接在
application
文件中配置spring.thymeleaf.cache=false
來(lái)實(shí)現(xiàn) 注意:不同的模板配置不一樣
熱部署主要步驟
- 在
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>
- 修改
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
- 修改 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......
- 修改了java類之后饭耳,IDEA 默認(rèn)是不自動(dòng)編譯的串述,而
- 配置完需要重啟一下觅赊,然后有修改的話項(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
重新編譯
- 點(diǎn)擊右上角
- 快捷鍵
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è)試
需要注意的是:
- 如果在和
main文件夾
平級(jí)的test文件夾
下新建了java文件夾
萝风,但是無(wú)法新建java class
文件 - 那么就需要右鍵文件夾
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):StandaloneMockMvcBuilder
和DefaultMockMvcBuilder
壕曼,分別對(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
- @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ì)象的描述
- @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 API
和SOAP 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的使用
- 在
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>
- 添加
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>
- 在
application.yml
添加緩存配置# Ehcache 緩存配置 cache: ehcache: config: classpath:ehcache.xml
- 在入口類添加
@EnableCaching
注解,表示開(kāi)啟緩存 - Java Bean 對(duì)象實(shí)現(xiàn)序列化栋豫,
public class User implements Serializable
- 在需要使用的地方使用現(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的使用
- 在
pom.xml
添加依賴<!--Quartz工具依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
- 添加
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......"); } }
- 構(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ā) |
操作代碼資源地址
參考資料
- 參考教程 ———— 兩天搞定SpringBoot框架
- 參考文檔 ———— JavaSpringBoot 中 @Autowired用法
- 參考文檔 ———— SpringBoot - @Configuration腐芍、@Bean注解的使用詳解(配置類的實(shí)現(xiàn))
- 參考文檔 ———— 【Spring Boot】Spring基礎(chǔ) —— 組合注解與元注解
- 參考文檔 ———— @RestController 和 @Controller 的區(qū)別
- 參考文檔 ———— MapperScan注解詳解
- 參考文檔 ———— Mapper.xml詳解
- 參考文檔 ———— MVC三層架構(gòu)(詳解)
- 參考文檔 ———— 配置devtools熱部署
- 參考文檔 ———— (十三)SpringBoot2.0熱部署Devtools原理
- 參考文檔 ———— 2021版IDEA沒(méi)有compiler.automake.allow.when.app.running
- 參考文檔 ———— SpringBoot基礎(chǔ)之MockMvc單元測(cè)試
- 參考文檔 ———— Ehcache詳細(xì)解讀
- 參考文檔 ———— spring boot接入ehcache
- 參考文檔 ———— SpringBoot(十二): validation常用注解
- 參考文檔 ———— SpringBoot之——Validator校驗(yàn)相關(guān)的注解
- 參考文檔 ———— 強(qiáng)悍的Spring之spring validation
- 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饧健!