SpringBoot筆記 SpringBoot文檔 官網: https://spring.io/projects/spring-boot 學習文檔: https://docs.spring.io/spring-boot/docs/current/reference/html/ 線上API: http ...
SpringBoot筆記
SpringBoot文檔
- 官網: https://spring.io/projects/spring-boot
- 學習文檔: https://docs.spring.io/spring-boot/docs/current/reference/html/
- 線上API: https://docs.spring.io/spring-boot/docs/current/api/
Spring Boot 是什麼
- Spring Boot 可以輕鬆創建獨立的、生產級的基於Spring 的應用程式
- Spring Boot 直接嵌入Tomcat、Jetty 或Undertow ,可以"直接運行" SpringBoot 應用程式
- Spring Boot有Web場景啟動器,會自動導入和Web相關的依賴
Springboot/Srping/SpringMVC之間的關係
- 關係大概是: Spring Boot > Spring > Spring MVC
- Spring MVC 只是Spring 處理WEB 層請求的一個模塊/組件, Spring MVC 的基石是Servlet
- Spring 的核心是IOC 和AOP, IOC 提供了依賴註入的容器, AOP 解決了面向切麵編程
- Spring Boot 是為了簡化開發, 推出的封神框架(約定優於配置[COC],簡化了Spring 項目的配置流程), SpringBoot 包含很多組件/架,Spring 就是最核心的內容之一,也包含SpringMVC
- Spring 家族,有眾多衍生框架和組件例如boot、security、jpa 等, 他們的基礎都是Spring
約定優於配置
- 約定優於配置(Convention over Configuration/COC),又稱按約定編程,是一種軟體設計規範, 本質上是對系統、類庫或框架中一些東西假定一個大眾化合理的預設值(預設值)
- 例如在模型中存在一個名為User 的類,那麼對應到資料庫會存在一個名為user 的表,只有在偏離這個約定時才需要做相關的配置(例如你想將表名命名為t_user 等非user 時才需要寫關於這個名字的配置)
- 簡單來說就是假如你所期待的配置與約定的配置一致,那麼就可以不做任何配置,約定不符合期待時, 才需要對約定進行替換配置
- 約定其實就是一種規範,遵循了規範,那麼就存在通用性,存在通用性,那麼事情就會變得相對簡單,程式員之間的溝通成本會降低,工作效率會提升,合作也會變得更加簡單
依賴管理
-
spring-boot-starter-parent 還有父項目, 聲明瞭開發中常用的依賴的版本號
-
並且進行自動版本仲裁, 即如果程式員沒有指定某個依賴jar 的版本,則以父項目指
定的版本為準
如何修改版本仲裁?
修改版本仲裁-方法一
在pom.xml中顯示的配置
修改版本仲裁-方法二
在spring-boot-starter-parent 的父項目 中修改即可
場景啟動器Starter
- 開發中我們引入了相關場景的starter,這個場景中所有的相關依賴都引入進來了,比如我們做web 開發引入了,該starter 將導入與web 開發相關的所有包
- SpringBoot 也支持第三方starter。第三方starter 不要從spring-boot 開始,因為這是官方spring-boot 保留的命名方式的。第三方啟動程式通常以項目名稱開頭。
- 也就是說:xxx-spring-boot-starter 是第三方為我們提供的簡化開發的場景啟動器
SpringBoot 自動配置了哪些?
- 自動配置Tomcat
- 自動配置SpringMVC
- 自動配置Web 常用功能: 比如字元過濾器
- 【預設掃描主程式所在包以及其子包】
如何修改預設掃描包結構?
設置 @SpringBootApplication(scanBasePackages="com.xxx")
如何修改SpringBoot預設配置?
在 resources/application.properties 文件中修改
- 預設配置最終會映射到某個類【屬性類】
在application.properties 自定義配置
-
通過 @Value(${ })獲取值
-
例如 my.website=http://www.baidu.com
@value(${my.website})//獲取方式: private String bdUrl(){ }
-
SpringBoot 所有的自動配置功能都在spring-boot-autoconfigure 包裡面
-
在SpringBoot 的自動配置包, 一般是XxxAutoConfiguration.java, 對應XxxxProperties.java
容器功能
Spring註解
Spring中傳統的註解依然可以使用
@Configuration註解
案例一
@Configuration//表示這是一個配置類【類似spring的bean.xml配置文件】
//當一個類被 @Configuration 標識 ,該類【bean】自己本身也會註入到容器中
public class BeanConfig {//配置類可以有多個, 就和Spring 可以有多個beans.xnl配置文件是一個道理.
@Bean // 程式員可以通過@Bean 註解註入bean對象到容器
// 給容器添加組件,就是Monster bean;
// 方法名(monster01),作為 bean 的 id/名字 ;
// 返回值(Monster) 表示 註入類型 是 Monster 類型 ;
// new Monster(200,"nmw",500,"fmq"); 就是註入到容器的bean的具體信息
public Monster monster01() {
return new Monster(200, "nmw", 500, "fmq");
}
- 方法名(monster01),作為 bean 的 id/名字 ;
- 返回值(Monster) 表示 註入類型 是 Monster 類型 ;
- new Monster(200,"nmw",500,"fmq"); 就是註入到容器的bean的具體信息
案例二
- 可以通過在註解 @Bean 中設置屬性 來指定bean的名字 @Bean("monster_nmw")
@Bean("monster_nmw")
// 也可以通過在註解 @Bean 中設置屬性 來指定bean的名字 @Bean("monster_nmw")
public Monster monster02() {
return new Monster(200, "nmw", 500, "fmq");
}
案例三
- @Configuration(proxyBeanMethods = true) ---proxyBeanMethods:代理bean 的方法
@Configuration(proxyBeanMethods = true)
public class BeanConfig {
@Bean
//預設單例註入
//多例模式 添加註解: @Scope("prototype")
public Monster monster01() {
return new Monster(200, "nmw", 500, "fmq");
}
- proxyBeanMethods:代理bean 的方法
- Full(proxyBeanMethods = true) 【保證每個@Bean 方法被調用多少次返回的組件都是單實例的, 是代理方式】
- Lite(proxyBeanMethods = false)【每個@Bean 方法被調用多少次返回的組件都是新創建的, 是非代理方式】
- 特別說明: proxyBeanMethods 是在調用@Bean 方法才生效,因此,需要先獲取BeanConfig 組件,再調用方法而不是直接通過SpringBoot 主程式得到的容器來獲取bean, 註意觀察直接通過ioc.getBean() 獲取Bean,proxyBeanMethods 值並沒有生效
- 如何選擇: 組件依賴必須使用Full 模式預設。如果不需要組件依賴使用Lite 模式 ;
- Lite 模式也稱為輕量級模式,因為不檢測依賴關係,運行速度快
@Import註解
@Configuration
@Import({Dog.class, Cat.class})//可以指定Class數組,可以註入指定類型的Bean ;預設組件 id 是 對應的類型的全類名
public class BeanConfig {}
- 可以指定Class數組,可以註入指定類型的Bean ;
- 預設組件 id 是 對應的類型的全類名(com.xxx.xx...)
@Conditional註解
- 條件裝配,滿足Conditional 指定的條件,才進行組件註入
- @Conditional 是一個根註解,下麵有很多擴展註解
- 例如 @ConditionalOnBean
@Bean
@ConditionalOnBean(name = "monster_nmw")
//【條件裝配】表示 只有在ioc容器中存在一個名字 為 monster_nmw 的bean,才能註入 dog01
public Dog dog01() {
return new Dog();
}
-
只有在ioc容器中存在一個名字 為 monster_nmw 的bean,才能註入 dog01
-
對name約束,對其他無關
-
有 其他擴展註解,對應不同的約束例如 :@ConditionalOnMissingBeanName(name="monster-nmw")
表示 沒有name="monster-nmw" 才會註入容器
-
如果@ConditionalOnBean 表示在某個類上,則該類所有的組件都要受到約束
@ImportResource
- 作用:原生配置文件引入, 也就是可以直接導入Spring 傳統的beans.xml ,可以認為是SpringBoot 對Spring 容器文件的相容.
@Configuration
//導入bean.xml文件
@ImportResource("classpath:beans.xml")
public class BeanConfig2 {
}
將beans.xml導入到配置類
配置綁定@ConfigurationProperties
- 使用Java 讀取到SpringBoot 核心配置文件application.properties 的內容,並且把它封裝到JavaBean 中
1.在application.properties 文件中設置 屬性 k-v 【屬性需要和JavaBean的屬性對應】
furn01.id=100
furn01.name=soft_chair!!
furn01.price=45678.9
2.在JavaBean上添加註解 @ConfigurationProperties(prefix = "furn01")
@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
private Integer id;
private String name;
private Double price;
}
註意事項
- 另一種綁定方式:在配置類上加上 @EnableConfigurationProperties(Furn.class)
- 如果application.properties 有中文, 需要轉成unicode 編碼寫入, 否則出現亂碼
yaml介紹
- yaml以數據作為中心,不以標記語言為中心
- yaml仍然是一種標記語言,但是以數據作為中心
- yaml非常適合用來做以數據為中心的配置文件
yaml基本語法
- 形式為 key: value 【註意: 後有空格】
- 區分大小寫
- 使用縮進表示層級關係
- 縮進推薦使用空格
- 縮進空格數不重要,只要相同層級的元素左對齊即可
- 字元串無需加引號
- yaml註釋使用 #
yaml數據類型
-
字面量:date,boolean,string,number,null
-
對象:鍵值對的集合 map,hash,set,object
行內寫法
k: {k1: v1,k2: v2,k3: v3}
換行寫法
k: k1: v2 k2: v2 k3: v3
-
數組 array,list,queue
行內寫法
k: [v1,v2,v3]
換行寫法
k: -v2 -v2 -v3
註意事項:
- application.properties 的優先順序比 application.yml 高,因此要避免首碼相同
- 字元串無需加引號,加引號不影響
靜態資源的訪問
基本介紹
-
只要靜態資源放在 類路徑下 :“classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/”
-
訪問方式:預設 項目根路徑/靜態資源名
註意事項
-
靜態資源訪問原理:靜態映射的 /**,也就是攔截所有請求。當請求進來,先判斷Controller能否處理,不能處理的請求交給靜態資源處理器,如果靜態資源找不到,響應404頁面
-
修改靜態資源訪問首碼【當與Controller路徑衝突時】
在application.yml配置‘
spring: mvc: static-path-pattern: /zyres/** #靜態資源首碼
-
修改靜態資源訪問路徑
在application.yml配置‘
web: resources: static-locations: [classpath:/img/] #添加預設靜態資源路徑
原先的預設路徑會被覆蓋,需要再配
Rest風格請求
-
Rest風格請求的核心Filter:HiddenHttpMethodFilter,表單請求會被HiddenHttpMethodFilter 攔截,獲取表單的 _method值,再判斷是PUT/PELETE/PATCH
-
如果需要Springboot支持 頁面表單的rest風格請求功能,需要在application.yml 啟用filter功能,否則無效
spring: mvc: hiddenmethod: filter: enabled: true #頁面表單支持rest風格
視圖解析器的配置
spring:
mvc:
view:
suffix: .html
prefix: /zyres/ #視圖解析器 <-這裡如果修改了static-path-pattern 需要保持一致
- 如果配置了視圖解析器,而controller的路徑和視圖路徑一致時,會走視圖解析器
接收參數註解
@PathVaiable
請求 :
<a href="/monster/100/king"></a>
@RequestMapping("/monster/{id}/{name}")
@ResponseBody
public String pathVariable(@PathVariable("id") Integer id,
@PathVariable("name") String name,
@PathVariable Map<String, String> map) {
System.out.println("id= " + id + ", name= " + name);
System.out.println("map= " + map);
return "success";
}
- @RequestMapping("/monster/{id}/{name}") 和 @PathVariable("id")相對應
- Integer id形參無所謂
- Map<String, String> map) ,map會存放所有 @PathVariable的 k-v
@RequestHeader
@RequestMapping("/requestHeader")
@ResponseBody
public String requestHeader(@RequestHeader("Host") String host,
@RequestHeader Map<String, String> header) {
System.out.println("host= " + host);
System.out.println("header= " + header);
return "success";
}
- @RequestHeader("Host")大小寫無所謂
- @RequestHeader Map<String, String> header),map獲取 @RequestHeader的 所有請求頭
@RequestParam
請求:
<a href="/hi?name=zy&fruit=apple&fruit=pear"></a>
@GetMapping("/hi")
@ResponseBody
public String hi(@RequestParam("name") String userName,
@RequestParam("fruit") List<String> fruits,//一個參數名對應多個值時 用List接收
@RequestParam Map<String, String> params) {
System.out.println("userName= " + userName);
System.out.println("fruits= " + fruits);
System.out.println("params= " + params);
return "success";
}
- @RequestParam("fruit") List
fruits,//一個參數名對應多個值時 用List接收 - <a href="/hi?name=zy 中的name 要和 @RequestParam("name") 註解中對應
- String userName形參無所謂’
- @RequestParam Map<String, String> params ,map獲取所有請求參數
- 但是k-v中k是唯一,所以獲取相同參數只有一個值會被放入 map
@CookieValue
@GetMapping("/cookie")
@ResponseBody
public String cookie(@CookieValue(value = "cookie_key",required = false) String cookie_value,
@CookieValue(value = "username",required = false) Cookie cookie) {
System.out.println("cookie_value= "+cookie_value);
System.out.println("username= "+cookie.getName()+"-"+cookie.getValue());
return "success";
}
- 當形參為 String 類型,會取出cookie對應的value
- 當形參為 Cookie 類型,會取出封裝好的cookie
@RequestBody
@PostMapping("/save")
@ResponseBody
public String save(@RequestBody String content) {
System.out.println("content= "+content);
return "success";
}
- 可以接收客戶端 json格式數據
- 可以獲取post請求體
@RequestAttribute
@PostMapping("/login")
@ResponseBody
public String login(@RequestAttribute String content) {
System.out.println("content= "+content);
return "success";
}
- 用來獲取Request域中的屬性
@SessionAttribute
-
用來獲取Session域中的屬性
-
用法和@RequestAttribute一致
複雜參數
- Springboot在響應客戶端請求時,也支持複雜參數。例如:map,model等
- map,model數據會放在request域
- RedirectAttribute 重定向攜帶數據
//響應註冊請求
@GetMapping("/register")
public String register(Map<String, Object> map,
Model mondel,
HttpServletResponse response) {
//將數據封裝到map或model
map.put("user", "zy");
map.put("job", "java後端開發");
mondel.addAttribute("sal", "8000");
//請求轉發
return "forward:/registerOk";
}
自定義對象參數-自動封裝
- springboot在響應客戶端請求時,也支持自定義對象參數
- 完成自動類型轉換與格式化
- 支持級聯封裝
轉換器
- Springboot在響應客戶端請求時,將提供的數據封裝成對象時,使用了內置的轉換器
- springboot也支持自定義轉換器,springboot提供了124內置轉換器
自定義轉換器
自定義轉換器--- 方式一
@Configuration(proxyBeanMethods = false)//Lite模式
public class WebConfig {
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
// 在addFormatters 中 添加自定義轉換器String->Car
// 添加的自定義轉換器 會註冊到 converters 容器中
// converters 底層是 ConcurrentHashMap 內置124個轉換器
registry.addConverter(new Converter<String, Car>() {
@Override
public Car convert(String s) {//s 就是傳入的需要轉換的數據
//加入自定義的轉換的業務代碼
if (!ObjectUtils.isEmpty(s)){
String[] split = s.split(",");
Car car = new Car();
car.setName(split[0]);
car.setPrice(Double.parseDouble(split[1]));
return car;
}
return null;
}
});
}
};
}
}
自定義轉換器--- 方式二
@Configuration(proxyBeanMethods = false)//Lite模式
public class WebConfig {
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
//方式二
//1.先創建自定義的轉換器
Converter<String, Car> zyConverter = new Converter<String, Car>() {
@Override
public Car convert(String s) {//s 就是傳入的需要轉換的數據
//加入自定義的轉換的業務代碼
if (!ObjectUtils.isEmpty(s)) {
String[] split = s.split(",");
Car car = new Car();
car.setName(split[0]);
car.setPrice(Double.parseDouble(split[1]));
return car;
}
return null;
}
};
registry.addConverter(zyConverter);//添加
//這裡可以添加多個自定義轉換器,但如果泛型一樣,後面的轉換器會覆蓋
//原因: 因為容器底層時CurrentHashMap,key是唯一,二key時泛型組合成的
}
};
}
}
Thymeleaf
Thymeleaf是什麼?
- Thymeleaf 是一個跟Velocity,FreeMarker類似的模板引擎,可完全替代
- Thymeleaf是一個java類庫,它是一個xml/xhtml/html5的模板引擎,可以作為mvc的web應用的view層
Thymeleaf的優點
- 實現JSTL,OGNL表達式的效果,語法相似
- Thymeleaf 模板頁面無需伺服器渲染,也可以被瀏覽器運行,頁面簡潔
- Springboot支持FreeMarker,Thymeleaf,Velocity
Thymeleaf的缺點
- 並不是一個高性能引擎,適用於單體應用
- 高併發應用依然選擇前後端分離更好
Thymeleaf機制
- Thymeleaf是伺服器渲染技術,頁面數據是在服務端進行渲染的
- 當用戶請求頁面,Thymeleaf模板引擎完成處理【服務端】,將頁面返回
- Thymeleaf並非前後端分離,是在伺服器端完成渲染
Thymeleaf語法
表達式
${...}
變數表達式,獲取請求域,session域,對象等值
@{...}
鏈接表達式,生成鏈接
#{...}
消息表達式,獲取國際化等值
~{...}
代碼塊表達式,類似jsp中include作用,映入公共片段
*{...}
選擇變數表達式,獲取上下文對象值
字面量
- 文本值:'zy','hello',...;數字:10,15.3,...;布爾值:true,false
- 空值: null
- 變數:name,age...
文本操作
字元串拼接 +
變數替換 |age=${age}|
運算符
-
數學運算 +,-,*,/,%
-
布爾運算 and,or
一元運算 !,not
-
比較運算
比較 ><,>=,<=(gt,lt,ge,le)
等式 ==,!=(eq,ne)
條件運算
- if-then:(if)?(then)
- if-then-else:(if)?(then):(else)
- Default : (value)?:(defaul value)
th屬性
1)th:text:文本替換;
2)th:utext:支持html的文本替換。
3)th:value:屬性賦值
4)th:each:遍歷迴圈元素
5)th:if:判斷條件,類似的還有th:unless,th:switch,th:case
6)th:insert:代碼塊引入,類似的還有th:replace,th:include,常用於公共代碼塊提取的場景
7)th:fragment:定義代碼塊,方便被th:insert引用
8)th:object:聲明變數,一般和*{}一起配合使用,達到偷懶的效果。
9)th:attr:設置標簽屬性,多個屬性可以用逗號分隔
攔截器Interceptor
- springboot項目,攔截器是開發中常用的手段,登陸驗證,性能檢查,日誌記錄等
基本介紹
- 編寫一個攔截器實現HandleInterceptor介面
- 攔截器註冊到配置類【實現WebMvcConfiguration 的 addInterceptors】
- 也可以直接實現WebMvcConfigurer介面
- 指定攔截規則
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")//攔截所有
.excludePathPatterns("/","/login","/images/**","/upload.html","/register"
,"/css/**");//指定放行
}
};
}
}
註意事項
- URI和URL的區別:URI唯一標識一個資源【網站內部】;URL可以提供找到該資源的路徑【帶主機和埠】
- URI = /manage.html
- URL = http://localhost:8080/manage.html
異常處理
基本介紹
- 預設情況下,springboot提供 /error 處理所有錯誤的映射
- 當出現錯誤時,springboot底層會請求轉發到 /error映射
- 比如當瀏覽器訪問不存在的路徑,響應一個"whitelable"錯誤視圖,以HTML格式呈現給用戶
- springboot底層預設由DefaultErrorViewResolver
攔截器和過濾器的區別
攔截器和過濾器使用範圍不同
- 過濾器實現的是javax.servlet.Filter介面,而這個介面實在Servlet規範中定義的,也就是說過濾器Filter的使用要依賴與Tomcat等容器,Filter只能在Web程式使用
- 攔截器是一個Spring組件,並由Spring容器管理,並不依賴Tomcat容器,是可以單獨使用的,不僅能應用在web工程,還能用於Application等程式
攔截器和過濾器觸發時機不同
-
過濾器Filter是在請求進入容器後,但在進入Servlet之前進行預處理,請求結果實在Servlet處理完以後。
-
攔截器實在請求進入Servlet後,進入Controller之前進行預處理,Controller渲染了對應的視圖後結束
-
請求
↓
Tomcat
↓
Filter
↓
Servlet
↓
Interceptor
↓
Controller
↓
-
過濾器不會處理 請求轉發,攔截器會處理請求轉發
自定義異常頁面
- 如果是用模板引擎,需要將自定義異常的頁面放在 /templates/error/路徑
- 如果沒有使用模板引擎,就放在靜態資源路徑下【四個預設】,"/resource/static/errpr/路徑"
- “classpath:/META-INF/resources/error/路徑","classpath:/resources/error/路徑", "classpath:/static/error/路徑", "classpath:/public/error/路徑”
- 先會根據狀態碼精確查找 (例如 404.html),若找不到,會去找 4xx.html
- 如果都沒有,會new 一個預設頁面返回
- 前端可以使用 th:text="${status}"取出狀態碼
全局異常
基本介紹
- @ControllerAdvice + @ExceptionHandler 處理全局異常
- 底層是ExceptionHandlerExceptionResolver支持的
- 作用:當發生異常時,不使用預設異常機制匹配xxx.html,而是通過全局異常機制,顯示指定的錯誤頁面
- 對比:自定義異常是根據狀態碼來決定 返回的html頁面;全局異常是根據Java異常類型來決定 返回的html頁面
如何獲取到異常發生的地方?
用HandlerMethod在形參上獲取
具體實現
@ControllerAdvice //標識全局異常處理器/對象 ,GlobalExceptionHandler 會被註入到spring容器
@Slf4j
public class GlobalExceptionHandler {
//編寫方法處理指定的異常
//Exception e 表示異常發生後,傳遞的異常對象
//Model model 可以存放錯誤信息到model,再放入到request域,帶到目標頁面顯示
// Class<? extends Throwable>[] value() default {};
@ExceptionHandler({ArithmeticException.class, NullPointerException.class,AccessException.class})
public String handleAritException(Exception e, Model model){
log.info("異常信息={}",e.getMessage());
model.addAttribute("msg",e);
return "/error/global";
}
}
- Exception e 表示異常發生後,傳遞的異常對象
- Model model 可以存放錯誤信息到model,再放入到request域,帶到目標頁面顯示
- @ControllerAdvice //標識全局異常處理器/對象 ,GlobalExceptionHandler 會被註入到spring容器
- @ExceptionHandler({ArithmeticException.class, NullPointerException.class,AccessException.class})指定捕獲哪些異常
自定義異常
基本介紹
- springboot提供的異常不滿足需求,程式員可以自定義異常
- @ResponseStatus + 自定義異常
- 底層是 ResponseStatusExceptionResolver ,底層調用response.sendError
- 當拋出自定義異常後,仍然會根據狀態碼去匹配xxx.html顯示
- 可以將自定義異常放在全局異常處理器處理,但仍然走全局異常
具體實現
//自定義異常,需要繼承Exception (編譯異常)/RuntionException(運行異常)
// 一般繼承RuntionException(運行異常)
@ResponseStatus(value = HttpStatus.BAD_GATEWAY)
public class AccessException extends RuntimeException{
//提供構造器,可以指定信息
public AccessException(String message){
super(message);
}
public AccessException(){
}
}
Springboot文件上傳
前端 enctype="multipart/form-data"
<form action="#" th:action="@{/register}" method="post" enctype="multipart/form-data">
用戶名:<input type="text" style="width: 150px" name="name"/><br/><br/>
電郵:<input type="text" style="width: 150px" name="email"/><br/><br/>
年齡:<input type="text" style="width: 150px" name="age"/><br/><br/>
職位:<input type="text" style="width: 150px" name="job"/><br/><br/>
頭像:<input type="file" style="width: 150px" name="header"/><br/><br/>
寵物:<input type="file" style="width: 150px" name="photos" multiple/><br/><br/>
<input type="submit" value="註冊"/>
<input type="reset" value="重新填寫"/>
</form>
類型一 將上傳的文件保存到指定目錄
@Controller
@Slf4j
public class UploadController {
//處理請求轉發-用戶註冊 可以完成文件上傳
@GetMapping("/upload.html")
public String upload() {
return "upload";
}
//處理用戶註冊
@PostMapping("/register")
@ResponseBody
public String register(@RequestParam("name") String name,
@RequestParam("email") String email,
@RequestParam("age") Integer age,
@RequestParam("job") String job,
@RequestParam("header") MultipartFile header,
@RequestParam("photos") MultipartFile[] photos) throws IOException {
//1.將上傳的文件保存到指定目錄
if (!header.isEmpty()) {
String originalFilename = header.getOriginalFilename();
File file = new File("d:\\temp_upload\\" + originalFilename);
header.transferTo(file);
}
//處理圖片
if (photos.length > 0) {
for (MultipartFile photo : photos) {
if (!photo.isEmpty()) {
String originalFilename = photo.getOriginalFilename();
File file = new File("d:\\temp_upload\\" + originalFilename);
photo.transferTo(file);
}
}
}
return "註冊用戶成功/文件上傳成功";
}
}
類型二 將上傳的文件保存到指定目錄
@Controller
@Slf4j
public class UploadController {
//處理請求轉發-用戶註冊 可以完成文件上傳
@GetMapping("/upload.html")
public String upload() {
return "upload";
}
//處理用戶註冊
@PostMapping("/register")
@ResponseBody
public String register(@RequestParam("name") String name,
@RequestParam("email") String email,
@RequestParam("age") Integer age,
@RequestParam("job") String job,
@RequestParam("header") MultipartFile header,
@RequestParam("photos") MultipartFile[] photos) throws IOException {
//2.動態創建目錄並保存
// D:\zy_springboot\springboot-thymeleaf-usersys\target\classes\static\images\xupload\\
//獲取當前年月日【解決分目錄】
LocalDate now = LocalDate.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String format = now.format(dtf);
System.out.println("format= "+format);
String path = ResourceUtils.getURL("classpath:").getPath();
path = path + "static/images/upload/"+format+"/";
File file = new File(path);
if (!file.exists()) {
//目錄不存在 就創建
file.mkdirs();
}
//【解決文件覆蓋問題】
String prefix = UUID.randomUUID().toString();
prefix = prefix +"_"+ System.currentTimeMillis()+"_";
if (!header.isEmpty()) {
String originalFilename = header.getOriginalFilename();
header.transferTo( new File(file.getAbsolutePath()+"/"+prefix+originalFilename));
}
//處理圖片
if (photos.length > 0) {
for (MultipartFile photo : photos) {
if (!photo.isEmpty()) {
String originalFilename = photo.getOriginalFilename();
photo.transferTo( new File(file.getAbsolutePath()+"/"+prefix+originalFilename));
}
}
}
return "註冊用戶成功/文件上傳成功";
}
}
Servlet/Filter/Listener在springboot如何註入
基本介紹
- 考慮到相容,springboot支持將Servlet/Filter/Listener註入spring容器,成為spring 的 bean
- 即 springboot開放了和原生web組件的相容
- 如果要使用原生web組件的開發,需要在主啟動器添加註解@ServletComponentScan(basePackages = "com.xxx.xx")指定要掃描的包,才會註入容器
- Servlet/Filter/Listener在springboot註入有兩種方式,
- 方式一是通過@WebServlet,@WebFilter,@WebListener註解註入
- 方式二是通過RegistrationBean方式註入
通過@WebServlet,@WebFilter,@WebListener註解註入
註入Servlet 【@WebServlet】
//有@WebServlet標識 表示: 將 Servlet_ 對應的bean 註入到容器
//@WebServlet(urlPatterns = {"/servlet01","/servlet02"})//映射的路徑
public class Servlet_ extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello Servlet_~");
}
}
- 註意:註入的原生的Servlet 不會被 SpringBoot攔截器 攔截 ---原因走原生的Servlet處理,而不是springboot的DispatchServlet
- 原因:
- 當多個Servlet都能處理同一層路徑,精確優先/最長首碼匹配原則,所以當請求/servlet時,會直接匹配註入的servlet
註入Filter【@WebFilter】
@WebFilter(urlPatterns = {"/css/*","/images/*"})
public class Filter_ implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("hello Filter_~");
HttpServletRequest request = (HttpServletRequest)servletRequest ;
System.out.println("URI= "+request.getRequestURI());
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("destroy...");
}
}
- 過濾器會被SpringBoot攔截器 攔截
註入Listener 【@WebListener 】
@WebListener
public class Listener_ implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
system.out.println("項目初始化");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContextListener.super.contextDestroyed(sce);
}
}
通過RegistrationBean方式註入
RegistrationBean方式-註入Servlet
// //註入Servlet
@Bean
public ServletRegistrationBean servlet_(){
Servlet_ servlet = new Servlet_();//創建原生的Servlet對象
//把servlet 和 ServletRegistrationBean 關聯
//"servlet01","servlet02" 是url-pattern
return new ServletRegistrationBean(servlet,"/servlet01","/servlet02");
}
RegistrationBean方式-註入Filter
//註入Filter
@Bean
public FilterRegistrationBean filter_(){
Filter_ filter = new Filter_();//創建原生的filter對象
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*","/images/*"));
return filterRegistrationBean;
}
RegistrationBean方式-註入Listener
//註入Listener
@Bean
public ServletListenerRegistrationBean listener_(){
Listener_ listener = new Listener_();//創建原生的listener對象
ServletListenerRegistrationBean servletListenerRegistrationBean =
new ServletListenerRegistrationBean(listener);
return servletListenerRegistrationBean;
}
內置的WebServlet【伺服器】切換
基本介紹
- Springboot支持的WebServlet:Tomcat,Jetty,Undertom
- Springboot啟動,web場景啟動器自動導入tomcat
- 支持切換WebServlet
如何配置內置的tomcat
-
可以通過application.yml完成配置【配置信息和ServletProperties.java關聯】
-
通過配置類進行配置
-
@Component public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { @Override public void customize(ConfigurableServletWebServerFactory factory) { factory.setPort(8080);//配置埠 } }
切換WebServlet
-
修改pom.xml文件,刪除tomcat依賴,引入undertow
-
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--排除tomcat starter--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
-
引入undertow
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
資料庫操作
- springboot預設使用JDBC+HikariDataSource
如何使用預設JDBC+HikariDataSource進行資料庫操作
-
引入data-jdbc starter
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
-
springboot並不知道具體要操作哪一種資料庫,需要在pom.xml中指定導入資料庫驅動,並指定對應版本
-
<!-- 引入mysql驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>
-
在application.yml中配置數據源
-
spring: datasource: url: jdbc:mysql://localhost:3306/furn_ssm2?useSSL=true&useUnicode=true&characterEncoding=UTF-8 username: root password: zy driver-class-name: com.mysql.jdbc.Driver
-
完成測試
-
@SpringBootTest//需要引入 spring-boot-starter-test 依賴 public class ApplicationTests { @Resource private JdbcTemplate jdbcTemplate; @Test public void contextLoads(){ BeanPropertyRowMapper<Furn> rowMapper = new BeanPropertyRowMapper<>(Furn.class); List<Furn> furns = jdbcTemplate.query("SELECT * FROM `furn`", rowMapper); for (Furn furn : furns) { System.out.println("furn= "+furn); } System.out.println(jdbcTemplate.getDataSource().getClass()); } }
整合Druid 和 springboot
基本介紹
-
Druid是Java語言中最好的資料庫連接池。Druid能夠提供強大的監控和擴展功能。
-
Druid提供了一個高效、功能強大、可擴展性好的資料庫連接池。
-
可以監控資料庫訪問性能,Druid內置提供了一個功能強大的StatFilter插件,能夠詳細統計SQL的執行性能,這對於線上分析資料庫訪問性能有幫助。
-
資料庫密碼加密。DruidDruiver和DruidDataSource都支持PasswordCallback。
-
SQL執行日誌,,監控你應用的資料庫訪問情況。
整合Druid 和 springboot【2種方式】
方式一 自定義方式整合
-
引入druid依賴
-
<!--引入druid依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.17</version> </dependency>
-
在配置類註入DataSource
-
@Configuration public class DruidDataSourceConfig { //編寫方法註入 DruidDataSource @ConfigurationProperties(prefix = "spring.datasource")//就可以和 application.yml相關聯【DataSource】 @Bean public DataSource dataSource() throws SQLException { DruidDataSource druidDataSource = new DruidDataSource(); //加入監控功能 druidDataSource.setFilters("stat,wall"); return druidDataSource; } //配置druid的監控功能 @Bean public ServletRegistrationBean statViewServlet() { StatViewServlet statViewServlet = new StatViewServlet(); ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*"); //設置init-parameter [設置用戶名和密碼] registrationBean.addInitParameter("loginUsername", "zy"); registrationBean.addInitParameter("loginPassword", "666666"); return registrationBean; } //配置 WebStatFilter 用於Web的監控功能 @Bean public FilterRegistrationBean webStatFilter() { WebStatFilter webStatFilter = new WebStatFilter(); FilterRegistrationBean<WebStatFilter> registrationBean = new FilterRegistrationBean<>(webStatFilter); //預設對所有請求進行監控 registrationBean.setUrlPatterns(Arrays.asList("/*")); //排除指定的url registrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return registrationBean; } }
方式二 引入druid starter方式整合
-
引入druid starter
-
<!-- 引入druid starter--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.17</version> </dependency>
-
在application.yml中配置druid和監控功能
-
#配置druid 和 監控功能 druid: stat-view-servlet: enabled: true login-username: jack login-password: 666 reset-enable: false #開啟web監控 web-stat-filter: enabled: true url-pattern: /* exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #開啟sql監控 filter: stat: slow-sql-millis: 1000 #慢查詢 log-slow-sql: true enabled: true #開啟防火牆監控 wall: enabled: true config: drop-table-allow: false select-all-column-allow: false
為什麼註入自己的DataSource,預設的HikariDataSource會失效?
原因: 因為預設的數據源是根據@ConditionalOnMissingBean判斷,如果自己沒有配,預設使用HikariDataSource;如果配置了,就用配置了的DataSource。
Springboot整合MyBatis
-
需要在application.yml種指定mapper.xml掃描的路徑
-
mybatis: # 指定要掃描的 Xxxmapper.xml mapper-locations: classpath:mapper/*.xml
-
在Mapper介面上可以通過添加@Mapper註解,註入容器
-
@Mapper //@Mapper就會掃描 並 將介面對象註入容器 public interface MonsterMapper { //根據id 返回monster Monster getMonsterById(Integer id); }
-
在application.yml中,可以通過 config-location 可以指定 mybatis-config.xml,來進行傳統mybatis方式的配置
-
mybatis: config-location: classpath:mybatis-config.xml
-
也可以直接在application.yml中配置mybatis【推薦】
-
mybatis: # 配置類型別名 type-aliases-package: com.zy88.springboot.bean configuration: # 配置日誌 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-
如果配置內容少,建議直接在application.yml中配置mybatis,如果內容很多,才考慮單獨做一個 mybatis-config.xml
Springboot整合MyBatis-Plus
基本介紹
- MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。
- 內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求
Springboot整合MyBatis-Plus
-
需要引入MyBatis-Plus starter【在meven倉庫中】
-
<!-- 引入Mybatis-Plus starter--> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>
-
在application.yml配置數據源
-
server: port: 9090 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hsp_mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8 username: root password: zy
-
在配置類註入DruidDataSource
-
@Configuration public class DruidDataSourceConfig { //編寫方法註入 DruidDataSource @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource() { DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } }
整合mapper【MyBatis-Plus與MyBatis的不同】
- mapper介面需要繼承BeseMapper<>
@Mapper
public interface MonsterMapper extends BaseMapper<Monster> {
//自定義方法
int insertSelective(Monster monster);
}
- BaseMapper 已經預設提供了很多crud方法,可以直接使用
- 如果 BaseMapper 提供的方法不能滿足業務需求,我們可以開發新的方法 ,併在MonsterMapper.xml配置
整合service【MyBatis-Plus與MyBatis的不同】
- service需要繼承父介面 ISercice<>
public interface MonsterService extends IService<Monster> {
//自定義方法
}
- IService介面聲明瞭很多方法,crud
- 如果不能滿足需求,可以再聲明需要的方法,然後在實現類實現即可
- 註意:MyBatis-Plus開發實現類 需要繼承 ServletImpl
@Service
public class MonsterServiceImpl
extends ServiceImpl<MonsterMapper, Monster>
implements MonsterService{
}
指定掃描某個包下的所有mapper介面
在主啟動器上添加@MapperScan(basePackages = {"com.xxx.xxx.xx"})
@MapperScan(basePackages = {"com.zy88.springboot.mybatisplus.mapper"})
@SpringBootApplication
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class,args);
}
}
@TableName作用
- 預設情況:如果類名首字母小寫和表名不一致,可以映射
- 當類名首字母小寫和表名不一致時,通過@TableName,在實體類上加@TableName("表名")進行映射
@TableName("monster_")
public class Monster {
private Integer id;
private Integer age;
private String name;
private String email;
//解決時區問題
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")//GMT 是格林尼治標準時間 ,如果需要時分秒加上 HH:mm:ss
private Date birthday;
private double salary;
private Integer gender;
}
- 為了開發方便可以添加MyBatisX插件
本文學習內容來自韓順平老師的課程
僅供個人參考學習