生活随笔
收集整理的這篇文章主要介紹了
后端学习 - SpringBoot
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
- SpringBoot 是整合 Spring 技術棧的一站式框架,是簡化 Spring 技術棧的快速開發腳手架
- 約定大于配置
文章目錄
- 一 概述
- 1 第一個 SpringBoot 項目
- 2 SpringBoot 特性:依賴管理
- 3 SpringBoot 特性:自動配置
- 二 SpringBoot 的 IOC容器
- 1 組件添加:@Configuration
- 2 組件添加:@Import
- 3 組件添加:@Conditional
- 4 引入原生配置文件:@ImportResource
- 5 配置綁定:@ConfigurationProperties
- 6 Lombok 的使用
- 三 yaml 配置文件
- 1 基本語法
- 2 使用示例
- 3 添加配置提示(自動補全)
- 四 實例:后端管理系統
- 1 靜態資源的配置與訪問
- 2 配置控制器
- 3 Thymeleaf 抽取頁面的相同元素
- 4 配置攔截器
- 5 文件上傳
- 6 錯誤處理
- 五 注入原生 Web 組件(Servlet,Filter,Listener)
- 1 使用 Servlet API(推薦)
- 2 使用 RegistrationBean
- 六 數據訪問
- 1 導入 JDBC 場景
- 2 切換 Druid 數據源
- 3 整合 MyBatis
- 七 單元測試
- 1 JUnit5
- 2 常用注解
- 3 斷言 assert
- 4 假設 assumption
- 5 嵌套測試
- 八 指標監控
一 概述
1 第一個 SpringBoot 項目
導入 maven 依賴
<parent><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-starter-parent
</artifactId><version>2.6.3
</version></parent><dependencies><dependency><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-starter-web
</artifactId></dependency></dependencies>
創建主程序類,作為啟動的入口,注意:啟動類的目錄一定要在 controller 等目錄的至少上一級,或者在 @SpringBootApplication 注解中添加 scanBasePackages 屬性
@SpringBootApplication(scanBasePackages
= "controller")
public class HelloApplication {public static void main(String[] args
) {SpringApplication.run(HelloApplication.class, args
);}
}
創建控制器類以及控制器方法,@RestController = @ResponseBody + @Controller,用于標注控制器類,該控制器的 所有方法 向瀏覽器返回 控制器方法的返回值
@RestController
public class HelloController {@RequestMapping("/hello")public String hello() {return "hello springboot";}
}
運行主程序類的 main 方法即可,無需更多配置
如果要修改某些配置,在 resources/application.properties 中修改即可,如:server.port=8888
如果要導出為 jar 包,需要在 maven 配置文件中添加:
<build><plugins><plugin><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-maven-plugin
</artifactId></plugin></plugins></build>
并執行 maven 的 clean + package 操作
2 SpringBoot 特性:依賴管理
- 自定義的 SpringBoot 項目的父項目 spring-boot-starter-parent,實現了依賴管理功能
- 父項目的父項目 spring-boot-dependencies 的 <properties> 標簽聲明了幾乎所有開發中常用的依賴的版本號,實現自動版本仲裁機制(即:引入依賴默認可以不寫版本,但是引入非版本仲裁的 jar,要寫版本號)
- 如果想使用依賴的指定版本,需要在當前項目的 maven 配置文件中的 <properties> 標簽聲明
1、查看spring-boot-dependencies里面規定當前依賴的版本 用的 key。
2、在當前項目里面重寫配置
<properties><mysql.version>5.1.43
</mysql.version></properties>
- 場景啟動器:spring-boot-starter-*,只要引入 starter,這個場景的所有常規需要的依賴都進行自動引入;所有的啟動器底層都依賴 SpringBoot 核心依賴:
<dependency><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-starter
</artifactId><version>2.6.3
</version><scope>compile
</scope>
</dependency>
3 SpringBoot 特性:自動配置
- 主程序所在包及其下面的所有子包里面的組件(需要 @Component、@Controller… 注解才能稱為組件,不加注解無法掃描)都會被默認掃描進來,不用顯式地配置組件掃描
- 各種配置擁有默認值,并按需加載所有自動配置項
- 主程序類的注解 @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan(主程序類所在包)
- 自動配置流程:
(Ⅰ) SpringBoot 加載所有的自動配置類(xxxxxAutoConfiguration類,而非組件)
(Ⅱ) 每個自動配置類按照條件生效,默認綁定配置文件指定的值(xxxxProperties類)
(Ⅲ) 生效的配置類就會給容器中裝配很多組件
(Ⅳ) 如果要自定義配置,可以選擇:創建 @Bean 替換底層組件,或修改組件獲取的配置文件(這些文件最終都映射到 application.properties)
二 SpringBoot 的 IOC容器
1 組件添加:@Configuration
- @Configuration 注解的類,相當于原來的 xml 配置文件
- 配置類本身也是組件
- 向 IOC 容器中注入 Bean,對 @Configuration 類中的方法使用 @Bean 注解,將方法的返回對象注入容器
- 默認情況下,注入容器的對象名為被注解的方法名,如果要修改則向 @Bean 中傳遞參數
@Configuration
class MyConfig {@Bean public Pet jerrymouse() {return new Pet("Jerry", 3);}
}
- 代理 Bean 方法:@Configuration(proxyBeanMethod = true) 時(Full 模式),對于 @Bean 注解的方法,如果直接被調用,方法返回的對象是單例的;如果是 @Configuration(proxyBeanMethod = false) (Lite 模式)則非單例
- Full / Lite 模式與組件依賴問題:
配置的組件之間無依賴關系,用 Lite 模式,加速容器啟動過程,減少判斷
配置類組件之間有依賴關系,用 Full 模式,組件單實例,保證依賴成立
2 組件添加:@Import
- 對類進行的注解
- 在 IOC 容器中創建組件,名字為類的全類名
@Import({User.class, Pet.class})
@Configuration(proxyBeanMethods
= true)
public class MyConfig {
}
3 組件添加:@Conditional
- 條件裝配:滿足指定的條件后進行組件裝配,可以注解類和方法
- 具有一系列的子注解,對應不同的情況
@ConditionalOnBean(name="..."):IOC容器具有指定 Bean 時執行當前組件的裝配
@ConditionalOnMissingBean(name="..."):IOC容器失去指定 Bean 時執行當前組件的裝配
…
4 引入原生配置文件:@ImportResource
- 用于注解配置類,導入 Spring 的 xml 配置文件
- 傳遞參數為配置文件的路徑: @ImportResource("classpath:myspringconfig.xml")
5 配置綁定:@ConfigurationProperties
- 目的是,使得 Java 讀取到 properties 文件中的內容,并且把它封裝到 JavaBean 中,以供隨時修改并使用,即:JavaBean 和配置文件的綁定
- @ConfigurationProperties 注解需要填入 prefix 屬性,以在配置文件中指定其對象的屬性值
@Component
@ConfigurationProperties(prefix
= "jjjerry")
public class Pet {private String name
;private int age
;...
}
- 如果是自定義類,在自定義類上注解 @ConfigurationProperties 即可;如果非自定義類,需要在配置類上額外注解 @EnableConfigurationProperties(Pet.class),它的作用是開啟 Pet 的配置綁定功能,并將 Pet 組件自動注冊到容器中
6 Lombok 的使用
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Person {private String name
;private String address
;
}
- @Slf4j 簡化日志記錄,為注解的類注入了 log 實例:
@Slf4j
@SpringBootApplication
public class Application {public static void main(String[] args
) {ConfigurableApplicationContext context
= SpringApplication.run(Application.class, args
);log
.info(String.valueOf(context
.getBean("wubai").toString()));}
}@Configuration
class MyConfiguration {@Beanpublic Person wubai() {return new Person("wubai", "taipei");}
}
三 yaml 配置文件
- 是一種面向數據的配置文件,推薦在配置組件屬性時使用
1 基本語法
大小寫敏感使用縮進表示層級關系縮進不允許使用tab,只允許空格縮進的空格數不重要,只要相同層級的元素左對齊即可'#'表示注釋使用 key: value 的形式,注意其中的空格字符串無需使用引號標注,使用引號時,單引號的轉義字符不起作用,雙引號起作用詳細的語法規則
2 使用示例
創建名為 wubai_wujunlin 的組件,并注入 IOC 容器:
@Component(value
= "wubai_wujunlin")
@ConfigurationProperties(prefix
= "wujunlin")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Person {private String name
;private String address
;private List<String> bandMates
;
}
依賴的 application.yaml:
wujunlin:name: 吳俊霖
address: 臺北
bandMates: [小朱
, 大貓
, Dino
]
3 添加配置提示(自動補全)
在 maven 配置文件添加:
<dependency><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-configuration-processor
</artifactId><optional>true
</optional>
</dependency><build><plugins><plugin><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-maven-plugin
</artifactId><configuration><excludes><exclude><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-configuration-processor
</artifactId></exclude></excludes></configuration></plugin></plugins></build>
四 實例:后端管理系統
1 靜態資源的配置與訪問
- 默認靜態資源在 resources 目錄下的 static 、public… 文件夾內
- 訪問時使用的路徑:當前項目根路徑/ + 靜態資源名
- 自定義訪問靜態資源使用的路徑:
spring:mvc:static-path-pattern: "/custom_static_url/**"
- 歡迎頁默認為靜態資源路徑下的 index.html
- 輸入地址 http://localhost:8080 即可訪問歡迎頁
- 在靜態資源目錄下的 favicon.ico 同樣會被自動解析
2 配置控制器
- 為了避免刷新頁面導致表單的重復提交,首次成功登陸后,在控制器方法中返回 "redirect:/main.html" 重定向到新的頁面
@Controller
public class IndexController {@GetMapping(value
= {"/login", "/"})public String loginPage() {return "login";}@PostMapping("/login")public String processLogin(User user
, HttpSession session
, Model model
) {if (!user
.getUsername().isEmpty() && !user
.getPassword().isEmpty()) { session
.setAttribute("loginUser", user
);return "redirect:/main.html"; } else {model
.addAttribute("msg", "賬號密碼錯誤");return "login";}}@GetMapping("/main.html") public String mainPage(HttpSession session
, Model model
) {if (session
.getAttribute("loginUser") != null) {return "main";} else {model
.addAttribute("msg", "未登錄");return "login";}}
}
3 Thymeleaf 抽取頁面的相同元素
官方文檔對于 th:insert, th:replace, th:include 的示例
<body><div th:insert="footer :: copy"></div><div th:replace="footer :: copy"></div><div th:include="footer :: copy"></div></body>…will result in:
<body><div><footer>© 2011 The Good Thymes Virtual Grocery
</footer></div><footer>© 2011 The Good Thymes Virtual Grocery
</footer><div>© 2011 The Good Thymes Virtual Grocery
</div></body>
實現步驟
引入命名空間 <html lang="en" xmlns:th="http://www.thymeleaf.org">創建公共部分的 html 頁面,使用 th:fragment 或 id 為公共部分命名
1 使用 fragment 屬性命名
<head th:fragment="commonheader"><meta charset="UTF-8"><title>表格頁面的公共部分
</title>...
</head>2 使用 id 屬性命名
<div id="leftmenu" class="left-side sticky-left-side">...
</div>
導入公共部分:
1 對于 th:fragment 命名的標簽,添加屬性 th:xx(replace/insert/include)="公共文件名 :: fragment屬性"
<div th:replace="common :: commonheader"></div>2 對于 id 命名的標簽,添加屬性 th:xx(replace/insert/include)="公共文件名 :: #id屬性"
<div th:replace="common :: #leftmenu"></div>
4 配置攔截器
- 攔截路徑為 /** 時,靜態資源的訪問也會被攔截,需要為靜態資源路徑添加放行
- 配置類:
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry
) {registry
.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") .excludePathPatterns("/", "/login", "/css/**", "/fonts/**", "/images/**", "/js/**"); }
}
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request
, HttpServletResponse response
, Object handler
) throws Exception {Object user
= request
.getAttribute("loginUser");if (user
!= null) {return true;} else {request
.getRequestDispatcher("/").forward(request
, response
);log
.warn("未登錄!!");return false;}}@Overridepublic void postHandle(HttpServletRequest request
, HttpServletResponse response
, Object handler
, ModelAndView modelAndView
) throws Exception {HandlerInterceptor.super.postHandle(request
, response
, handler
, modelAndView
);}@Overridepublic void afterCompletion(HttpServletRequest request
, HttpServletResponse response
, Object handler
, Exception ex
) throws Exception {HandlerInterceptor.super.afterCompletion(request
, response
, handler
, ex
);}
}
5 文件上傳
html 的 from 標簽
<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data"><div class="form-group"><label for="exampleInputFile">上傳單個文件
</label><input type="file" name="singleImage" id="exampleInputFile1"></div><div class="form-group"><label for="exampleInputFile">上傳多個文件,添加 multiple 屬性
</label><input type="file" name="multiImage" id="exampleInputFile2" multiple></div></form>
控制器方法
使用 MultipartFile 參數類型獲取上傳文件,其方法 transferTo(...) 用于保存文件到服務器
@PostMapping("/upload")public String upload(@RequestPart("headerImage") MultipartFile headerImg
,@RequestPart("lifeImage") MultipartFile[] lifeImg
) throws IOException {if (!headerImg
.isEmpty()) {String fileName
= headerImg
.getOriginalFilename();headerImg
.transferTo(new File("E:\\" + fileName
));}return "redirect:/main.html";}
6 錯誤處理
- SpringBoot 默認的錯誤處理機制:error/下的4xx,5xx頁面會被自動解析,發生錯誤時,有精確的錯誤狀態碼頁面就匹配精確,沒有就找 4xx / 5xx;如果都沒有就觸發白頁
五 注入原生 Web 組件(Servlet,Filter,Listener)
1 使用 Servlet API(推薦)
- 使用 @WebServlet,@WebFilter,@WebListener 注解對應的類,并在啟動類注解 @ServletComponentScan 傳入 Web 組件位置
@WebServlet(urlPatterns
= "/")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req
, HttpServletResponse resp
) throws ServletException, IOException {}
}
@WebFilter(urlPatterns
= {"/**"})
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig
) throws ServletException {System.out
.println("過濾器初始化");}@Overridepublic void doFilter(ServletRequest servletRequest
, ServletResponse servletResponse
, FilterChain filterChain
) throws IOException, ServletException {System.out
.println("執行過濾操作");filterChain
.doFilter(servletRequest
, servletResponse
);}@Overridepublic void destroy() {System.out
.println("過濾器銷毀");}
}
@WebListener
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce
) {System.out
.println("監聽到項目初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce
) {System.out
.println("監聽到項目銷毀");}
}
2 使用 RegistrationBean
@Configuration
public class MyRegistConfig {@Beanpublic ServletRegistrationBean myServlet(){MyServlet myServlet
= new MyServlet();return new ServletRegistrationBean(myServlet
,"/my","/my02");}@Beanpublic FilterRegistrationBean myFilter(){MyFilter myFilter
= new MyFilter();FilterRegistrationBean filterRegistrationBean
= new FilterRegistrationBean(myFilter
);filterRegistrationBean
.setUrlPatterns(Arrays.asList("/my","/css/*"));return filterRegistrationBean
;}@Beanpublic ServletListenerRegistrationBean myListener(){MySwervletContextListener mySwervletContextListener
= new MySwervletContextListener();return new ServletListenerRegistrationBean(mySwervletContextListener
);}
}
六 數據訪問
1 導入 JDBC 場景
- 創建項目時,在 Spring Initializer 中勾選 JDBC 即可
<dependency><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-starter-jdbc
</artifactId></dependency>
- 默認的數據源是 HikariDataSource
- 常規配置
spring:datasource:driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123url: jdbc
:mysql
://localhost
:3306/test
2 切換 Druid 數據源
<dependency><groupId>com.alibaba
</groupId><artifactId>druid-spring-boot-starter
</artifactId><version>1.2.8
</version></dependency>
spring:datasource:driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123url: jdbc
:mysql
://localhost
:3306/test
druid:aop-patterns: com.atguigu.admin.*
filters: stat
,wall
stat-view-servlet: enabled: truelogin-username: admin
login-password: admin
resetEnable: falseweb-stat-filter: enabled: trueurlPattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'filter: stat: slow-sql-millis: 1000logSlowSql: trueenabled: truewall:enabled: trueconfig:drop-table-allow: false
3 整合 MyBatis
…
七 單元測試
1 JUnit5
- JUnit 5 = JUnit Platform(基礎框架) + JUnit Jupiter(核心) + JUnit Vintage(向下兼容)
- JUnit Platform: 在JVM上啟動測試框架的基礎,不僅支持Junit自制的測試引擎,其他測試引擎也都可以接入
- JUnit Jupiter: JUnit Jupiter 提供了 JUnit5 的新的編程模型,是 JUnit5 新特性的核心。內部 包含了一個測試引擎,用于在Junit Platform上運行
- JUnit Vintage: JUnit Vintage提供了兼容JUnit4.x,Junit3.x的測試引擎
2 常用注解
- @Test :標注方法是測試方法
- @ParameterizedTest:表示方法是參數化測試
- @RepeatedTest:重復執行測試方法
- @DisplayName:為測試類或者測試方法設置展示名稱
- @BeforeEach :在每個單元測試之前執行
- @AfterEach :在每個單元測試之后執行
- @BeforeAll :在所有單元測試之前執行,方法需要 static 修飾
- @AfterAll :在所有單元測試之后執行,方法需要 static 修飾
- @Tag :表示單元測試類別
- @Disabled :不執行測試類或測試方法
- @Timeout :測試方法運行如果超過了指定時間,將會返回錯誤
- @ExtendWith :為測試類或測試方法提供擴展類引用
3 斷言 assert
簡單斷言
方法說明
| assertEquals | 判斷兩個對象或兩個原始類型是否相等 |
| assertEquals | 判斷兩個對象或兩個原始類型是否相等 |
| assertNotEquals | 判斷兩個對象或兩個原始類型是否不相等 |
| assertSame | 判斷兩個對象引用是否指向同一個對象 |
| assertNotSame | 判斷兩個對象引用是否指向不同的對象 |
| assertTrue | 判斷給定的布爾值是否為 true |
| assertFalse | 判斷給定的布爾值是否為 false |
| assertNull | 判斷給定的對象引用是否為 null |
| assertNotNull | 判斷給定的對象引用是否不為 null |
數組斷言
- 通過 assertArrayEquals(...) 方法來判斷兩個對象或原始類型的數組是否相等
- 對于對象類型數組,比較的方式是邏輯等于,即調用 equals 方法
@Test
@DisplayName("array assertion")
public void array() {assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
組合斷言
- 要求一系列斷言同時滿足
- 使用 lambda 表達式提供方法實參(lambda 表達式對應函數式編程)
@Test
@DisplayName("assert all")
public void all() {assertAll("Math",() -> assertEquals(2, 1 + 1),() -> assertTrue(1 > 0));
}
異常斷言
- assertThrows 方法需要的參數:異常類型的 class 屬性,需要拋出異常的語句的 lambda 表達式
@Test
@DisplayName("異常測試")
public void exceptionTest() {Assertions.assertThrows(ArithmeticException.class, () -> System.out
.println(1 % 0));
}
超時斷言
@Test
@DisplayName("超時測試")
public void timeoutTest() {Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
快速失敗
@Test
@DisplayName("fail")
public void shouldFail() {fail("This should fail");
}
4 假設 assumption
- 假設作為單元測試的前提條件,如果前提條件不滿足則沒有進行測試的必要
- 不滿足的斷言會使得測試方法失敗;不滿足的前置條件只會使得測試方法的執行終止,而不會引起測試失敗
- assumeTrue 和 assumFalse 確保給定的條件為 true 或 false,不滿足條件會使得測試執行終止
- assumingThat 的參數是表示條件的布爾值和對應的 Executable 接口的實現對象,只有條件滿足時,Executable 對象才會被執行;當條件不滿足時,測試執行并不會終止
@DisplayName("前置條件")
public class AssumptionsTest {private final String environment
= "DEV";@Testpublic void simpleAssume() {assumeTrue(Objects.equals(this.environment
, "DEV"));assumeFalse(() -> Objects.equals(this.environment
, "PROD"));}@Testpublic void assumeThenDo() {assumingThat(Objects.equals(this.environment
, "DEV"),() -> System.out
.println("In DEV"));}
}
5 嵌套測試
- 目的是將測試過程結構化,把相關的測試方法組織在一起
- 對測試類及其內部類使用 @Nested 注解,實現嵌套測試
@DisplayName("A stack")
class TestingAStackDemo {Stack<Object> stack
;@Testvoid isInstantiatedWithNew() {new Stack<>();}@Nestedclass WhenNew {@BeforeEachvoid createNewStack() {stack
= new Stack<>();}@Testvoid isEmpty() {assertTrue(stack
.isEmpty());}@Nested@DisplayName("after pushing an element")class AfterPushing {String anElement
= "an element";@BeforeEachvoid pushAnElement() {stack
.push(anElement
);}@Test@DisplayName("it is no longer empty")void isNotEmpty() {assertFalse(stack
.isEmpty());}}}
}
八 指標監控
- 微服務在云上部署以后,都需要對其進行監控、追蹤、審計、控制等。SpringBoot 抽取了Actuator 場景,使得每個微服務可獲得生產級別的應用監控、審計等功能
1 開啟方法
引入場景依賴
<dependency><groupId>org.springframework.boot
</groupId><artifactId>spring-boot-starter-actuator
</artifactId></dependency>
配置暴露端點(endpoint)及暴露方式
management:endpoints:enabled-by-default: true web:exposure:include: '*'
訪問 http://localhost:8080/actuator/... 監控對應指標
2 常用端點
- Health:健康狀況
- Metrics:運行時指標
- Loggers:日志記錄
總結
以上是生活随笔為你收集整理的后端学习 - SpringBoot的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。