先說一些廢話
雖然我的作業中更多的是與資料庫打交道,但是作為一個Coder,我覺得掌握前后端的Web技術來說是非常有必要的,
不僅可以幫助我們在作業中更好的理解其他崗位與你對接的人他的作業痛點,也能在公司需要人手的時候成為一個有力的應急幫手,比如之前公司的資料中臺我就參與架構和部分開發任務,更重要的是我私下里可以運用一些快速框架來搭建一些有意思的網站,比如我的個人主頁和個人博客都是我自學java和js所做出來的作品,
所以今天我希望整合一些我以往的經驗和看過的教程檔案,來寫一篇文章,幫助你在一天之內通過這篇文章快速學習SpringBoot框架以及各種開發必備的工具與插件!!!
MVC
什么是MVC
- MVC三層架構是指:視圖層 View、服務層 Service,與持久層 Dao,它們分別完成不同的功能
- View 層:用于接收用戶提交請求的代碼在這里撰寫
- Service 層:系統的業務邏輯主要在這里完成
- Dao 層:直接操作資料庫的代碼在這里撰寫
- 為了更好的降低各層間的耦合度,在三層架構程式設計中,采用面向抽象編程,即上層對下層的呼叫,是通過介面實作的,而下層對上層的真正服務提供者,是下層介面的實作類
- 服務標準(介面)是相同的,服務提供者(實作類)可以更換,這就實作了層間解耦合
MVC 架構程式的作業流程
- 用戶通過 View 頁面向服務端提出請求,可以是表單請求、超鏈接請求、AJAX 請求等
- 服務端 Controller 控制器接收到請求后對請求進行決議,找到相應的 Model 對用戶請求進行處理
- Model 處理后,將處理結果再交給 Controller
- Controller 在接到處理結果后,根據處理結果找到要作為向客戶端發回的回應 View 頁面,頁面經渲染(資料填充)后,再發送給客戶端
使用xml還是注解
- 應用的基本配置使用xml,比如資料源和資源檔案等
- 業務開發使用注解,比如service注入bean
- 但是xml越來越多導致越來越臃腫,最終發展到使用完全基于注解開發
注解
宣告Bean注解
@Component 組件沒有明確規定其角色,作用在類級別上宣告當前類為一個業務組件,被
Spring IOC 容器維護
@Service 在業務邏輯層(Service)類級別進行宣告
@Registory 在資料訪問層(Dao)類級別進行宣告
@Controller 在展現層(MVC)使用,標注當前類為一個控制器
注入Bean注解
@Autowired 它可以對類成員變數、方法及建構式進行標注,完成自動裝配的作業,通過
@Autowired的使用來消除set、get方法
@Inject 作用同上,是JSR-330 標準
@Resource 作用同上,是JSR-250 標準
以上三種注解在Set方法或屬性上宣告,一般情況下更習慣宣告在屬性上,代碼簡潔清晰
配置與獲取Bean注解
@Configuration 將當前類宣告為一個配置類,相當于一個xml組態檔
@ComponentScan 自動掃描包下標注有@Repository @Service @Controller
@Component 注解的類并有Spring IOC 容器進行實體化和維護
@Bean 作用于方法上,宣告當前方法的回傳值是一個Bean物件,相當于xml檔案中<bean>宣告當前方法回傳一個bean物件
@Value 獲取properties檔案指定的key/value
pom.xml
作用是添加坐標相關配置,主要是各種依賴jar包
組合注解和元注解
所謂元注解其實就是可以注解到別的注解上的注解,被注解的注解稱之為組合注解,組合注解具備元注解的功能,主要的作用是消除重復注解
自定義注解
個性化的定義自己所需要的功能并宣告一個注解,簡化工程,可以參考文章————SPRINGBOOT自定義注解學習
常用注解
可以參考文章————SpringBoot常用注解集合詳細學習,這里后期會補上說明
@RestController、@ResponseBody、@RequestBody
- 相當于
@Controller + @ResponseBody兩個注解的結合,回傳JSON資料不需要在方法前面加@ResponseBody注解了,
但使用@RestController這個注解,就不能回傳jsp、html頁面,視圖決議器無法決議jsp、html頁面v @ResponseBody表示該方法的回傳結果直接寫入HTTP response body中,一般在異步獲取資料時使用(也就是AJAX),
在使用@RequestMapping后,回傳值通常決議為跳轉路徑,但是加上@ResponseBody后回傳結果不會被決議為跳轉路徑,而是直接寫入HTTP response body中,
比如異步獲取JSON資料,加上@ResponseBody后,會直接回傳JSON資料@RequestBody將 HTTP 請求正文插入方法中,使用適合的 HttpMessageConverter 將請求體寫入某個物件
@MapperScan、@Mapper
- @Mapper注解:
- 作用:在介面類上添加了@Mapper,在編譯之后會生成相應的介面實作類
- 添加位置:介面類上面
- 如果想要每個介面都要變成實作類,那么需要在每個介面類上加上
@Mapper注解,比較麻煩,解決這個問題用@MapperScan注解
- @MapperScan注解:
- 作用:指定要變成實作類的介面所在的包,然后包下面的所有介面在編譯之后都會生成相應的實作類
- 添加位置:是在Springboot啟動類上面添加
- 添加
@MapperScan("com.winter.da")注解以后,com.winter.dao包下面的介面類,在編譯之后都會生成相應的實作類
習慣大于配置目標
Spring Boot 的目標是快速運行,快速創建web應用,并獨立機型部署(jar包方式,war包方式),相比于Spring框架是全新重寫的框架
核心配置
修改Banner圖示
主要是通過修改/src/main/resources目錄下的banner.txt檔案,如果沒有則默認使用SpringBoot初始Banner
可以個性化制作Banner的網站制定相應的txt檔案
全域配置
默認是application.properties或者application.yml
坐標依賴都配置在pom.xml中,如果添加了依賴以后標紅可以使用Maven -> Reload project即可
入口類依靠組合注解@SpringBootApplication
@SpringBootConfiguration 本身是一個配置類,啟動類啟動的時候會加載
@EnableAutoConfiguration 組合了@AutoConfigurationPackage&@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage 底層是一個@Import(AutoConfigurationPackage.Registrar.class),其會把啟動類的包下組合都掃描到Spring容器中
@AutoConfigurationImportSelector 讀取大量的自動配置類,完成自動配置,其讀取的是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配置————區分生產和開發環境
通過在application.yml中設定spring.profiles.active=test/dev/prod來動態切換不同環境,例如:
# 開發環境組態檔
application-dev.yml
server:
prot: 8098
# 測驗環境組態檔
application-test.yml
server:
prot: 8097
# 生產環境組態檔
application-prod.yml
server:
prot: 8099
# 主組態檔
application.yml
spring:
profiles:
active: dev
日志配置
SpringBoot默認使用LogBack日志系統,一般主流的日志都是用log4j日志系統
如果重復啟動Spring專案,可能會有埠占用的報錯
- 思路是殺死占用埠的行程即可,主要是下面兩個命令
- 使用
netstat -aon|findstr "被占用的埠"或者tasklist |findstr "行程名稱"查詢到埠的行程號 - 使用
taskkill /f /t /im "行程名稱"或者taskkill /f /t /pid "行程PID"殺死行程即可
事務控制
宣告式事務
可以參考文章————SpringBoot宣告式事務的簡單運用詳細學習,這里后期會補上說明
主要應用在新增修改洗掉上,應用注解即可
全域例外
使用@ControllerAdvice配合@ExceptionHandler
可以參考文章————Springboot系列-@ControllerAdvice使用詳細學習,這里后期會補上說明
此注解其實是一個增強的Controller,使用這個Controller,可實作三個方面的功能,因為這是SpringMVC提供的功能,所以可以在springboot中直接使用
- 全域例外處理 (@ExceptionHandler)
- 全域資料系結 (@InitBinder)
- 全域資料預處理 (@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 = https://www.cnblogs.com/fx67ll/archive/2022/04/27/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;
}
}
資料校驗
為什么要進行后端資料校驗
資料的校驗是互動式網站一個不可或缺的功能,前端的js校驗可以涵蓋大部分的校驗職責,如用戶名唯一性,生日格式,郵箱格式校驗等等常用的校驗,
但是一般前端傳來的資料是不可信的,前端校驗過了,后端也應該重新校驗,因為不排除用戶繞過瀏覽器直接通過Http工具向后端請求的情況,
所以服務端的資料校驗也是必要的,可以防止臟資料落到資料庫中,如果資料庫中出現一個非法的郵箱格式,也會讓運維人員頭疼不已,
如何進行后端資料校驗
SpringBoot中一般使用Spring Validation來進行后端資料校驗,它是對Hibernate Validation進行了二次封裝,
在SpringMVC模塊中添加了自動校驗,并將校驗資訊封裝進了特定的類中- 在使用時我們只需要引入
spring-boot-starter-web依賴即可,該模塊會自動依賴spring-boot-starter-validation
Spring Validation 常用注解
@Null:被注釋的元素必須為
null
@NotNull:被注釋的元素不能為null,可以為空字串
@AssertTrue:被注釋的元素必須為true
@AssertFalse:被注釋的元素必須為false
@Min(value):被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
@Max(value):被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
@DecimalMin(value):被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
@DecimalMax(value):被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
@Size(max,min):被注釋的元素的大小必須在指定的范圍內
@Digits(integer,fraction):被注釋的元素必須是一個數字,其值必須在可接受的范圍內
@Past:被注釋的元素必須是一個過去的日期
@Future:被注釋的元素必須是一個將來的日期
@Pattern(value):被注釋的元素必須符合指定的正則運算式
@Email:被注釋的元素必須是電子郵件地址
@Length:被注釋的字串的大小必須在指定的范圍內
@Range:被注釋的元素必須在合適的范圍內
@URL:被注解的元素必須是一個URL
@NotEmpty:用在集合類上,不能為null,并且長度必須大于0
@NotBlank:只能作用在String上,不能為null,而且呼叫trim()后,長度必須大于0
自定義注解
可以參考文章————Spring自定義注解(validation)詳細學習,這里后期會補上說明
示例代碼
/com/fx67ll/springboot/controller/UserController.java在傳參的位置添加@Vaild注解表示這里的引數需要校驗,需要注意JSON格式和表單格式傳過來的引數例外會有些區別,需要在后面注意// 添加用戶 @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中私有欄位上使用注解來校驗,不貼所有代碼了,僅貼部分重點代碼@NotBlank(message = "用戶名稱不能為空!") private String userName; @NotBlank(message = "用戶密碼不能為空!") @Length(min = 6, max = 20, message = "密碼長度最少六位且最多二十位!") private String userPwd; - 在全域自定義例外攔截中
/com/fx67ll/springboot/exceptions/TestGlobalExceptionHandler.java向用戶回傳錯誤代碼和資訊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 = https://www.cnblogs.com/fx67ll/archive/2022/04/27/Exception.class) @ResponseBody public ResultInfo exceptionHandler(Exception exception) { ResultInfo resultInfo = new ResultInfo(); resultInfo.setCode(978); resultInfo.setMsg("全域例外攔截,操作失敗!"); // 全域資料校驗,注意!!!使用 json 請求體呼叫介面,校驗例外拋出 MethodArgumentNotValidException if (exception instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) exception; resultInfo.setCode(1023); resultInfo.setMsg(methodArgumentNotValidException.getBindingResult().getFieldError().getDefaultMessage()); } return resultInfo; } }
靜態資源
默認配置下,我們可以在resources資源目錄下存放web應用靜態資源檔案
自定義靜態資源路徑,可以通過在spring.resources.static-locations后面追加一個配置classpath:/你自定義的配置目錄/,例如:
# application.yml
spring:
resources:
# 多個目錄使用逗號隔開
static-loaction: classpath:/public/,classpath:/static/,classpath:/fx67ll/
打包和部署
jar包
- 一般用于撰寫依賴工具包
- 打包
- 在IDEA
Run/Debug Configurations下Command line配置clean complie package -Dmaven.test.skip=true執行打包命令 target目錄得到待部署的專案檔案
- 在IDEA
- 部署
- 在dos視窗中,執行命令
java -jar jar包所在的本地目錄
- 在dos視窗中,執行命令
war包
- 在生產環境中最為常見的部署方式
- 修改
pom.xml,設定打包模式為war包<groupId>com.fx67ll</groupId> <artifactId>springboot-quickstart</artifactId> <version>0.1.0</version> <!--設定為war包模式--> <packaging>war</packaging> - 忽略內嵌Tomcat
<!--設定為外部已提供,表示忽略--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> - 配置生成的war包名稱
<build> <!--設定war包名稱--> <finalName>fx67ll-springboot-quickstart-test</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> - 修改
Starter類,添加容器啟動加載檔案(類似讀取web.xml檔案)- 這里通過繼承
SpringBootServletInitiallizer類并重寫configure方法來實作 - 在部署專案的時候指定外部Tomcat讀取專案入口方法
@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); } } - 這里通過繼承
- 打包
- 在IDEA
Run/Debug Configurations下Command line配置clean complie package -Dmaven.test.skip=true執行打包命令 target目錄得到待部署的專案檔案
- 在IDEA
- 部署并訪問
- 放置到外部tomcat中,執行bin目錄下start腳本即可
熱部署
熱部署,就是在應用正在運行的時候升級軟體,卻不需要重新啟動應用,主要應用在開發程序中
熱部署原理
spring-boot-devtools是一個為開發者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去,
原理是在發現代碼有更改之后,重新啟動應用,但是速度比手動停止后再啟動還要更快,更快指的不是節省出來的手工操作的時間- 其深層原理是使用了兩個
ClassLoader,一個Classloader加載那些不會改變的類(第三方Jar包),另一個ClassLoader加載會更改的類,稱為restart ClassLoader,
這樣在有代碼更改的時候,原來的restart ClassLoader被丟棄,重新創建一個restart ClassLoader,由于需要加載的類相比較少,所以實作了較快的重啟時間,大概在5秒以內
devtools原理
- devtools會監聽classpath下的檔案變動,并且會立即重啟應用(發生在保存時機)注意:因為其采用的虛擬機機制,該項重啟是很快的
- devtools可以實作頁面熱部署(即頁面修改后會立即生效,這個可以直接在
application檔案中配置spring.thymeleaf.cache=false來實作 注意:不同的模板配置不一樣
熱部署主要步驟
- 在
pom.xml中添加依賴,同時添加devtools生效標志插件<!--熱部署插件devtools--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <!--表示當前這個專案被繼承之后,這個不向下傳遞--> <optional>true</optional> </dependency> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!--在原有的基礎上添加--> <configuration> <!--如果沒有該配置,熱部署插件devtools不生效--> <fork>true</fork> </configuration> </plugin> - 修改
application.yml全域組態檔,在application.yml中配置spring.devtools.restart.enable=false,此時restart類加載器還會初始化,但不會監視檔案更新spring: # 熱部署配置 devtools: restart: enabled: true # 設定重啟的目錄,添加目錄的檔案需要restart additional-paths: src/main/java # 解決專案啟動重新編譯后介面報404的問題 poll-interval: 3000 quiet-period: 1000 - 修改 IDEA 配置
- 修改了java類之后,IDEA 默認是不自動編譯的,而
spring-boot-devtools又是監測classpath下的檔案發生變化才會重啟應用,所以需要設定 IDEA 的自動編譯 - 設定自動配置
File -> Settings -> Build -> Complier -> Build Project automatically 修改Register屬性,執行快捷鍵ctrl + shift + alt + /,選擇Register,勾上Complier autoMake allow when app running- 注意 IDEA 2021.2.3 版本中沒有上面的選項,遷移到了
File -> Settings -> Tools -> Advanced Settings -> Complier -> Allow auto-make to start......
- 修改了java類之后,IDEA 默認是不自動編譯的,而
- 配置完需要重啟一下,然后有修改的話專案會自動更新,但是如果是自動觸發的話,會造成頻繁更新,對硬體有一定的負擔,所以可以改成手動觸發模式
- 點擊右上角
Run/Debug Configurations - 選擇下拉
Configuration -> Spring Boot -> Running Application Update Policies -> On 'Update' action - 選擇
Update classes and resources - 如果有更新可以,使用快捷鍵
Ctrl + F10重新編譯
- 點擊右上角
- 快捷鍵
Ctrl + F9,使用熱部署重新啟動
單元測驗
依賴
<!--單元測驗-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Service業務層————業務邏輯方法測驗
需要注意的是:
- 如果在和
main檔案夾平級的test檔案夾下新建了java檔案夾,但是無法新建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業務方法測驗
*
* Junit中的RunWith注解 表示該類是單元測驗的執行類
* SpringRunner 是 spring-test 提供的測驗執行單元類(是Spring單元測驗中SpringJUnit4ClassRunner的新名字)
* SpringBootTest注解 是執行測驗程式的引導類
*/
@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("單元測驗開始......");
}
@Test
public void testQueryUserById() {
logger.info("測驗根據用戶id查詢......");
User user = userService.queryUserById(1);
logger.info("用戶記錄: {}", user.toString());
}
@Test
public void testSelectUserListByParams() {
logger.info("測驗根據分頁條件查詢用戶串列......");
UserQuery userQuery = new UserQuery();
PageInfo<User> pageInfo = userService.selectUserListByParams(userQuery);
logger.info(pageInfo.toString());
}
@After
public void after() {
logger.info("單元測驗結束......");
}
}
controller控制層————介面方法測驗
使用MockMVC進行測驗
MockMvc是由spring-test包提供,實作了對Http請求的模擬,能夠直接使用網路的形式,轉換到Controller的呼叫,使得測驗速度快、不依賴網路環境,
同時提供了一套驗證的工具,結果的驗證十分方便
什么是Mock
在面向物件的程式設計中,模擬物件mock object是以可控的方式模擬真實物件行為的假物件,
在編程程序中,通常通過模擬一些輸入資料,來驗證程式是否達到預期結果
介面MockMvcBuilder
提供一個唯一的build方法,用來構造MockMvc,
主要有兩個實作:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分別對應兩種測驗方式,
即獨立安裝和集成Web環境測驗(并不會集成真正的web環境,而是通過相應的Mock API進行模擬測驗,無須啟動服務器),
MockMvcBuilders提供了對應的創建方法standaloneSetup方法和webAppContextSetup方法,在使用時直接呼叫即可,
# 示例代碼
# PS:雖然提示測驗通過,但是控制臺一直沒有列印出回傳資訊的記錄,后期有空看看
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;
/**
* 模擬測驗用戶串列查詢
* 其實就在模擬真實環境下前端對后端發起的請求
*/
@Test
public void apiTestSelectUserListByParams() throws Exception {
logger.info("開始模擬發送查詢用戶串列的請求......");
// 構建請求
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/user/list")
.contentType("text/html") // 設定請求頭資訊
.accept(MediaType.APPLICATION_JSON); // 設定請求Accept頭資訊
// 發送請求
ResultActions perform = mockMvc.perform(requestBuilder);
// 校驗請求結果
perform.andExpect(MockMvcResultMatchers.status().isOk());
// 獲取執行完成后回傳的結果
MvcResult mvcResult = perform.andReturn();
// 得到執行后的回應
MockHttpServletResponse response = mvcResult.getResponse();
// 列印結果
logger.info(String.valueOf(response.getContentLength()));
logger.info("回應狀態: ", response.getStatus());
logger.info("回應資訊: ", response.getContentAsString());
logger.info("結束模擬發送查詢用戶串列的請求......");
}
@Test
public void apiTestQueryUserByUsername() throws Exception {
logger.info("開始模擬根據用戶名查詢用戶記錄的請求......");
// 構建請求并發送
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/user/name/admin"))
.andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
// 列印結果
logger.info("回應狀態: ", mvcResult.getResponse().getStatus());
logger.info("回應資訊: ", mvcResult.getResponse().getContentAsString());
logger.info("結束模擬根據用戶名查詢用戶記錄的請求......");
}
}
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 注解說明詳細學習,這里后期會補上說明
@Api
主要是用在請求類上,用于說明該類的作用
# 示例
@Api(tags = "xx模塊")
@ApiOperation
主要是用在請求的方法上,說明方法的作用
# 示例
@ApiOperation(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/xx方法的作用", notes = "xx方法的備注說明")
@ApiImplicitParams、@ApiImplicitParam
主要是用在請求的方法上,說明方法的引數
# 詳細引數說明
@ApiImplicitParams:用在請求的方法上,包含一組引數說明
@ApiImplicitParam:對單個引數的說明
name:引數名
value:引數的說明、描述
required:引數是否必須必填
paramType:引數放在哪個地方
· query --> 請求引數的獲取:@RequestParam
· header --> 請求引數的獲取:@RequestHeader
· path(用于restful介面)--> 請求引數的獲取:@PathVariable
· body(請求體)--> @RequestBody User user
· form(普通表單提交)
dataType:引數型別,默認String,其它值dataType="Integer"
defaultValue:引數的默認值
# 單個引數示例
@ApiImplicitParam(name = "xxx", value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/xxx", required = true, paramType = "path", dataType = "String", defaultValuehttps://www.cnblogs.com/fx67ll/archive/2022/04/27/= "")
# 多個引數示例
@ApiImplicitParams({
@ApiImplicitParam(name = "xxxa", value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/xxxa", required = true, paramType = "body", dataType = "String", defaultValuehttps://www.cnblogs.com/fx67ll/archive/2022/04/27/= ""),
@ApiImplicitParam(name = "xxxb", value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/xxxb", required = true, paramType = "body", dataType = "String", defaultValuehttps://www.cnblogs.com/fx67ll/archive/2022/04/27/= ""),
})
@ApiResponses、@ApiResponse
主要是用在請求的方法上,說明錯誤回應的資訊
# 詳細引數說明
@ApiResponses:回應狀態的說明,是個陣列,可包含多個 @ApiResponse
@ApiResponse:每個引數的說明
code:數字,例如400
message:資訊,例如"請求引數沒填好"
response:拋出例外的類
# 多個引數示例,一般回應都是多個code,所以不寫單個引數的示例了
@ApiResponses({
@ApiResponse(code = 200, message = "請求成功"),
@ApiResponse(code = 578, message = "請求引數錯誤"),
@ApiResponse(code = 404, message = "請求路徑沒有或頁面跳轉路徑不對")
})
@ApiModel、@ApiModelProperty
- @ApiModel 經常用于請求的入參物件和回應回傳值物件的描述
- 入參是物件,即 @RequestBody 時, 用于封裝請求(包括資料的各種校驗)資料
- 回傳值是物件,即 @ResponseBody 時,用于回傳值物件的描述
- @ApiModelProperty 用于每個屬性上面,說明屬性的含義
# 示例
@ApiModel(description = "用戶物體類")
public class User {
@ApiModelProperty(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/用戶名", required = true, example = "0")
private Integer id;
@ApiModelProperty(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/用戶ID", required = true, example = "fx67ll")
private String userName;
@ApiModelProperty(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/用戶密碼", required = true, example = "xxxxxxxx")
private String userPwd;
}
分布式快取工具Ehcache
什么是Ehcache
EhCache是一個純Java的行程內快取框架,具有快速、精干等特點,是Hibernate中默認CacheProvider,
Ehcache是一種廣泛使用的開源Java分布式快取,主要面向通用快取,Java EE和輕量級容器,
它具有記憶體和磁盤存盤,快取加載器,快取擴展,快取例外處理程式,一個gzip快取servlet過濾器,支持REST API和SOAP API等特點,
SpringCache相關注解
SpringBoot快取實作內部使用SpringCache實作快取控制,這里集成Ehcache實際上是對SpringCache抽象的一種實作
可以參考文章————Spring Cache 簡介詳細學習,這里后期會補上說明
@EnableCaching
開啟快取功能,一般放在啟動類上
@CacheConfig
當我們需要快取的地方越來越多,你可以使用@CacheConfig(cacheNames = {"cacheName"})注解在Class之上來統一指定value的值,
這時可省略value,如果你在你的方法依舊寫上了value,那么依然以方法的value值為準
@Cacheable
根據方法對其回傳結果進行快取,下次請求時,如果快取存在,則直接讀取快取資料回傳;如果快取不存在,則執行方法,并把回傳的結果存入快取中,一般用在查詢方法上
注意value后面要使用ehcache.xml檔案中所列的cache.name
# 單個引數示例代碼
@Cacheable(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/fx67llCache", key = "#xxx")
# 多個引數示例,采用拼接的方式
@Cacheable(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/fx67llCache", key = "#xxx.xxx + '-' + #xxx.xxx + '-' + #xxx.xxx")
@CachePut
使用該注解標志的方法,每次都會執行,并將結果存入指定的快取中,其他方法可以直接從回應的快取中讀取快取資料,而不需要再去查詢資料庫,一般用在新增方法上
# 示例代碼
@CachePut(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/fx67llCache", key = "#xxx.xxx")
@CacheEvict
使用該注解標志的方法,會清空指定的快取,一般用在更新或者洗掉方法上
# 示例代碼
@CacheEvict(value = "https://www.cnblogs.com/fx67ll/archive/2022/04/27/fx67llCache", key = "#xxx")
@Caching
該注解可以實作同一個方法上同時使用多種注解
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分為記憶體和磁盤兩級,此屬性定義磁盤的快取位置,引數解釋如下: user.home – 用戶主目錄 user.dir – 用戶當前作業目錄 java.io.tmpdir – 默認臨時檔案路徑 --> <diskStore path="D:\Java\test-ehcache-cache"/> <!-- defaultCache:默認快取策略,當ehcache找不到定義的快取時,則使用這個快取策略,只能定義一個, --> <!-- name:快取名稱, maxElementsInMemory:快取最大數目 maxElementsOnDisk:硬碟最大快取個數, eternal:物件是否永久有效,一但設定了,timeout將不起作用, overflowToDisk:是否保存到磁盤,當系統當機時 timeToIdleSeconds:設定物件在失效前的允許閑置時間(單位:秒),僅當eternal=false物件不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大, timeToLiveSeconds:設定物件在失效前允許存活時間(單位:秒),最大時間介于創建時間和失效時間之間,僅當eternal=false物件不是永久有效時使用,默認是0.,也就是物件存活時間無窮大, diskPersistent:是否快取虛擬機重啟期資料 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. diskSpoolBufferSizeMB:這個引數設定DiskStore(磁盤快取)的快取區大小,默認是30MB,每個Cache都應該有自己的一個緩沖區, diskExpiryThreadIntervalSeconds:磁盤失效執行緒運行時間間隔,默認是120秒, memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理記憶體,默認策略是LRU(最近最少使用),你可以設定為FIFO(先進先出)或是LFU(較少使用), clearOnFlush:記憶體數量最大時是否清除, memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,默認策略)、FIFO(先進先出)、LFU(最少訪問次數), FIFO,first in first out,這個是大家最熟的,先進先出, LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點就是講一直以來最少被使用的,如上面所講,快取的元素有一個hit屬性,hit值最小的將會被清出快取, LRU,Least Recently Used,最近最少使用的,快取的元素有一個時間戳,當快取容量滿了,而又需要騰出地方來快取新的元素的時候,那么現有快取元素中時間戳離當前時間最遠的元素將被清出快取, --> <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注解,表示開啟快取 - Java Bean 物件實作序列化,
public class User implements Serializable - 在需要使用的地方使用現關注解,實作快取可以減少從資料庫查詢的次數
定時調度工具Quartz
可以參考文章————Quartz定時調度詳細學習,這里后期會補上說明
什么是Quartz
在日常專案運行中,我們總會有需求在某一時間段周期性的執行某個動作,比如每天在某個時間段匯出報表,或者每隔多久統計一次現在在線的用戶量等,
在SpringBoot中有Java自帶的java.util.Timer類,也可以在啟動類添加@EnableScheduling注解引入定時任務環境
Quartz的使用
- 在
pom.xml添加依賴<!--Quartz工具依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> - 添加
job包并撰寫job任務,實作job介面,并在execute方法中實作自己的業務邏輯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 { // 獲取整理好的日期時間 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 查詢觸發器名稱和觸發器屬于哪個分組 TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey(); //列印日志 logger.info("當前觸發器是: " + triggerKey.getName() + ",它所屬的組別是: " + triggerKey.getGroup() + "----------觸發時間: " + simpleDateFormat.format(new Date()) + "-->" + "Hello fx67ll Spring Boot Quartz......"); } } - 構建調度配置類,創建JobDetail實體并定義Trigger注冊到scheduler,啟動scheduler開啟調度
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 /** * 具體的可以被執行的調度程式 */ public JobDetail jobDetailTestQuartz(){ return JobBuilder.newJob(TestQuartzJob.class).storeDurably().build(); } @Bean /** * 第一個測驗觸發器,主要是配置引數提示什么時候呼叫 * 應用場景有比如定時發送郵件之類的 */ public Trigger triggerTestQuartzFirst(){ SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule() // 每五秒執行一次 .withIntervalInSeconds(1) // 永久重復,一直執行下去 .repeatForever(); return TriggerBuilder.newTrigger() // 設定觸發器名稱和分組 .withIdentity("triggerTestQuartzFirst","groupTestQuartz") .withSchedule(simpleScheduleBuilder) .forJob(jobDetailTestQuartz()) .build(); } @Bean /** * 第二個測驗觸發器 */ public Trigger triggerTestQuartzSecond(){ return TriggerBuilder.newTrigger() // 設定觸發器名稱和分組 .withIdentity("triggerTestQuartzSecond","groupTestQuartz") // 這里是通過定義運算式來表示每5秒執行一次,后續再深入研究下 .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *")) .forJob(jobDetailTestQuartz()) .build(); } }
附錄
操作代碼目錄說明
| springboot-quickstart | springboot-mybatis | springboot-mybatis-crud | springboot-mybatis-crud-prod |
|---|---|---|---|
| 快速入門 | 整合mybatis | 整套crud操作 | 生產環境開發 |
操作代碼資源地址
- springboot-quickstart
- springboot-mybatis
- springboot-mybatis-crud
- springboot-mybatis-crud-prod
參考資料
- 參考教程 ———— 兩天搞定SpringBoot框架
- 參考檔案 ———— JavaSpringBoot 中 @Autowired用法
- 參考檔案 ———— SpringBoot - @Configuration、@Bean注解的使用詳解(配置類的實作)
- 參考檔案 ———— 【Spring Boot】Spring基礎 —— 組合注解與元注解
- 參考檔案 ———— @RestController 和 @Controller 的區別
- 參考檔案 ———— MapperScan注解詳解
- 參考檔案 ———— Mapper.xml詳解
- 參考檔案 ———— MVC三層架構(詳解)
- 參考檔案 ———— 配置devtools熱部署
- 參考檔案 ———— (十三)SpringBoot2.0熱部署Devtools原理
- 參考檔案 ———— 2021版IDEA沒有compiler.automake.allow.when.app.running
- 參考檔案 ———— SpringBoot基礎之MockMvc單元測驗
- 參考檔案 ———— Ehcache詳細解讀
- 參考檔案 ———— spring boot接入ehcache
- 參考檔案 ———— SpringBoot(十二): validation常用注解
- 參考檔案 ———— SpringBoot之——Validator校驗相關的注解
- 參考檔案 ———— 強悍的Spring之spring validation
- json格式校驗并顯示錯誤_使用 Spring Validation 優雅地進行引數校驗
我是 fx67ll.com,如果您發現本文有什么錯誤,歡迎在評論區討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~ ??
轉發請注明參考文章地址,非常感謝!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/465019.html
標籤:其他
上一篇:Java面試題資料合集
