Spring Annotation 筆記
這邊主要整理了我使用或是遇到的Spring Annotation資料查詢與統整的紀錄
API 相關 @Annotation
@RestController
將class設置為外部控制器
@RestControllerAdvice
等同於@ControllerAdvice + @ResponseBody
@ControllerAdvice為可在宣告的函式中使用@ExceptionHandler, @InitBinder或 @ModelAttribute註解的方法
@ExceptionHandler
攔截所有控制器所發出的exception,並返回body型式
@RequestMapping
控制器裡面的方法,使之成為外部請求
若要設置GET method, 如下
(也可以改成 POST, PUT, DELETE)
定義一組restful api前綴路由
ex : @RequestMapping("/api/v1")
1 | "/api/v1") ( |
要使用的話得在postman中用 /api/v1/hello
HTTP動作Annotation
@PostMapping
@GetMapping
@PutMapping
@DeleteMapping
@RequestBody
可以接收Body參數,得透過class宣告一組object來接收
1 | class Car { |
1 | "/api/v1") ( |
@RequestHeader、@CookieValue
處理request header部分的注解:
Request Header的內容
1 | Host localhost:8080 |
透過 @RequestHeader("")接受其Header值
1 | @RequestMapping("/displayHeaderInfo.do") |
@SessionAttributes
該註解用來綁定HttpSession中的attribute對象的值,便於在方法中的參數里使用。
該註解有value、types兩個屬性,可以通過名字和類型指定要使用的attribute 對象;
1 |
|
參考資料:
Spring MVC常用注解@PathVariable、@RequestHeader、@CookieValue、@RequestParam、@RequestBody、@SessionAttributes、@ModelAttribute
https://www.cnblogs.com/EasonJim/p/8323017.html
@JsonProperty (重點,遇到接不到request的值,用這就對了)
用來接收application/json中,有大小不一型別的變數
ex: Postman script
1 | { |
若要接到 PHONE或Website,需要定義 @JsonProperty(“PHONE”), @JsonProperty(“Website”)
1 |
|
參考資料
Spring REST consuming JSON uppercase vs lowercase
https://stackoverflow.com/questions/26890398/spring-rest-consuming-json-uppercase-vs-lowercase
驗證相關的Annotation
@Valid與@Validated
負責驗證有被定義校正的參數或object
先產生要校正的實體類(class)
1 | public class Foo { |
於@Controller中 使用Valid做校正
1 | @Controller |
@Validate 與 @Valid差異
@Valid能進行嵌套驗證, @Validate不行
因為@Valid能加在成員屬性上,反而@Validated不能用在成員屬性。
舉例:
1 | public class Item { |
然而 Prop class如下
1 | public class Prop { |
現在我們有個ItemController接受一個Item的參數,想要對Item進行驗證,如下所示:
1 |
|
在上圖中,如果Item實體的props屬性不額外加註釋,只有@NotNull和@Size,無論入參採用@Validated還是@Valid驗證,Spring Validation框架只會對Item的id和props做非空和數量驗證,不會對props字段裡的Prop實體進行字段驗證,也就是@Validated和@Valid加在方法參數前,都不會自動對參數進行嵌套驗證</ span>
:::info
這邊指的嵌套(Nested)驗證,指的是若class Item中還有一個變數List
:::
要進行嵌套驗證的話得在 class Props中加入@Valid
1 | public class Item { |
補充 負責校驗的Annotation
1 | @Null 被註釋的元素必須為 null |
補充: 用BindingResult
接收@Valid拋出來的錯誤訊息
假設有驗證錯誤的物件為 BindingResult bindingResult
可透過bindResult取得錯誤資訊
舉例:
1 | public class FlightDTO { |
若使用@Valid對FlightDTO做參數驗證,假設有一Request少輸入terminal資訊,就會發出bindingResult訊息,其中包含:
1 | List<FieldError> fieldErrors = bindingResult.getFieldErrors(); |
:::info
BindingResult為Error的子介面
BindingResult
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/BindingResult.html
Error:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/Errors.html
:::
參考資料:
使用spring validation完成数据后端校验
https://www.cnkirito.moe/spring-validation/
@Validated和@Valid区别:Spring validation验证框架对入参实体进行嵌套验证必须在相应属性(字段)加上@Valid而不是@Validated
https://blog.csdn.net/qq_27680317/article/details/79970590
操作數據庫相關數據相關的Annotation
@Entity
表示是一個對應到DB Table的物件
@Id
聲明該欄位為主鍵
@GeneratedValue
指定ID生成的策略,若沒有設置的化, Hibernate對應的是為一個Not null的物件,得自行設定id到物件內。
但通常會自行在新增資料時產生ID, 故@Id與@GeneratedValue會常常同時出現
因為Hibernate會遇見不同的Database,所以有各種不同的生成策略:
GenerationType.Auto
Hibernate會根據採用的Database為何,來決定要用 GenerationType.Identity 或 GenerationType.SEQUENCE。
(大部分的情況都會採用 GenerationType.SEQUENCE)
GenerationType.IDENTITY
透過auto-incremented database column來產生primary key.
常見的MySQL和MMSQL都採用該方式,相對應的DDL語言為以下所示:
1 | id BIGINT NOT NULL AUTO_INCREMENT |
GenerationType.SEQUENCE
設定該策略,通常也會給入另一個Annotation @SequenceGenerator
,如下
1 |
|
若沒有指定,Hibernate會使用預設的SequenceGenerator
可以看到若指定 sequenceGenerator的name為author_seq, Hibernate就會在 author_seq
這個table查找下一個id值為多少
注意,在Postgres情況下不適合用該方法
https://stackoverflow.com/questions/4288740/hibernate-use-of-postgresql-sequence-does-not-affect-sequence-table/4502062#4502062
GenerationType.SEQUENCE
當不希望應用程式與某一種 Database Engine 綁死的時候,可以使用這種方法,透過另外一個表格來定義 ID
會透過SQL,建立存放各種column的seqeunce
1 | CREATE TABLE APP_SEQ_STORE ( APP_SEQ_NAME VARCHAR(255) NOT NULL, APP_SEQ_VALUE BIGINT NOT NULL, PRIMARY KEY(APP_SEQ_NAME) ); |
Reference: https://thoughts-on-java.org/jpa-generate-primary-keys/
@IdClass 复合主键
复合主键由多个主键字段组成。每个主键字段必须是上面列出的支持类型之一。
例如,以下项目实体类的主键由两个字段组成:
1 | .class) (ProjectId |
在ProjectId.class中聲明兩個主鍵值
1 | Class ProjectId { |
@Embeddable
嵌入式主键
表示复合主键的另一种方法是使用可嵌入的类
1 |
|
@Column
宣告該變數與資料庫欄位的對映
1 | 20) (nam=”category_name” length= |
參考資料:
SPRING中常用的注解(@ENTITY,@TABLE,@COLUMN,@REPOSITORY,@SERVICE)https://www.cnblogs.com/hoojjack/p/6568920.html
JPA 主键@Id、@IdClass、@Embeddable、@EmbeddedId
https://blog.csdn.net/tracycater/article/details/78319021
@Data
@Data 自動產生 getter(), setter(), toString(), 節省一大堆代碼的神Annotation
前置作業: 引入lombok
要使用 @Data 注解要先引入lombok
1 | lombok為一個Library,可以用簡單的註解形式來簡化代碼,提高開發效率。 |
如何使用lobok
- 在
maven
中添加依賴
1 | <dependency> |
- 在編譯器中添加插件
以IDEA為例,在setting的plugin裡搜索lombok plugin,安裝插件。
直接在Class上加上@Data即可
例如一个简单的Person Class
1 | public class Person { |
使用了 @Data
1 |
|
在按快捷鍵 Ctrl + F12
,可以查找到set,get,toString 方法。
使用 @Data 註解就可以有下面幾個註解的功能: @ToString、@Getter、@Setter、@EqualsAndHashCode、@NoArgsConstructor 。
:::info
常用的幾個註解:
@Data : 注在類上,提供類的get、set、equals、hashCode、canEqual、toString方法
@Setter : 注在屬性上,提供 set 方法
@Getter : 注在屬性上,提供 get 方法
構造函數
@AllArgsConstructor
会生成一个包含所有变量,同时如果变量使用了NotNull annotation , 会进行是否为空的校验,
全部参数的Constructor函数的自动生成,该注解的作用域也是只有在实体类上,参数的顺序与属性定义的顺序一致。
範例:
1 | import lombok.AllArgsConstructor; |
@NoArgsConstructor
產生沒有參數的建構子
generate a constructor with no parameters.
@RequiredArgsConstructor
会生成一个包含常量(final),和标识了@NotNull的变量 的构造方法。
@EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
@Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log
:::
:::warning
注意的是,同时使用@Data 和 @AllArgsConstructor 后 ,默认的无参构造函数失效,如果需要它,要重新设置 @NoArgsConstructor
:::
參考資料
@Data注解 与 lombok
https://www.jianshu.com/p/c1ee7e4247bf
学习Spring Boot:(十五)使用Lombok来优雅的编码
https://blog.wuwii.com/springboot-15.html
Spring載入Bean與標示為Bean有關的Annotation
@Bean
定義可共物件化的類別,叫做Bean,並且放置在Spring Ioc Container中並且給其管理,等待被呼叫使用。
配置方式
1. 程式碼Java Code配置
Spring 的@Bean通常宣告在掛有@Configuration的Spring配置類別中的方法前,例如宣告一個 AppConfig.java,若有超過一個以上的bean,使用 @Qualifier給予名稱
AppConfig.java
1 |
|
定義Calculator的介面
Calculator.interface
1 | public interface Calculator { |
定義一個實作Calculator的類別
CalculatorImpl.java
1 | package com.will.advanced.demo.bean; |
取得註冊的bean的方式
1. 使用@Autowire 與 @Qualifier
然後在 CommandLineRunner中使用 @AutoWire使用@Bean
,然而若要Autowired的類別對象是介面的話,且介面有很多的實作子類別
(AddCalculator, SubCalculator, MulCalculator)
那得透過 @Qualifier來指名是哪一個子類別
CommandLineAppStartupRunner.java
1 |
|
2. 使用getBean()
CommandLineAppStartupRunner.java
1 |
|
補充: 使用CommandlineRunner讓Spring設置可以先被載入,然後可透過run()定義自訂義執行的內容
https://dzone.com/articles/spring-boot-applicationrunner-and-commandlinerunne
3. xml檔案配置
上面的寫法等同在 appConfig.xml
宣告:
1 | <beans> |
@ComponentScan: 掃描指定package中掛有@Component的類別,自動註冊包含的bean
不過一般在沒有特殊需求的情況下都會使用@ComponentScan掃描指定package中掛有@Component的類別來自動註冊為bean。
而會使用@Bean的時機為,當要被註冊為bean的類別建構步驟或邏輯比較複雜,此時就需要@Bean讓你可以在構造bean的方法內撰寫構造的詳細邏輯,而@ComponentScan就無法滿足比較細微的配置。
例如在 service層中新增一個 TestService class
透過@Component將TestService註冊成Bean
1 |
|
透過@ComponentScan可使用@Component註冊的bean,
1 |
|
參考資料
Spring: A Head Start 🔥 — Beans Configuration (Part 2)
https://medium.com/omarelgabrys-blog/spring-a-head-start-beans-configuration-part-2-4a8c239b070a
@Scope: 定義Bean被引用時要怎樣被使用
- singleton:在Spring IoC Container,該bean只會有單一實例(a single instance),此為Spring預設值
- prototype:在Spring IoC Container中,該bean可以有多個實例(any number of object instances)
- request: 在每一次的HTTP Request,spring container會根據loginAction bean的定義來建立一個全新的instance,而且僅在目前的request中有效,所以可以放心的去更改instance的內部狀態,請求結束,request scope的bean instance會被destroy
- session:針對某個HTTP Session,spring container會根據userPreference bean的定義來建立一個全新的instance,同樣的,和request scope一樣,可以放心的去更改instance內部狀態。
- global-session:僅在portlet為基礎的Web應用下有作用。Porlet的規範中定義了global session的概念。
參考資料:
Spring Bean Scope 學習
https://kevingo75.blogspot.com/2012/03/spring-bean-scope.html
補充: 什麼是Spring IoC (Inversion of Control) container.
Inversion of Control, or IoC for short, is a process in which an object defines its dependencies without creating them. This object delegates the job of constructing such dependencies to an IoC container.
用一柱話描述IoC: class不用自己主動new欲依賴class的instance,而是透過外部 (main()方法) 以建構子、setter或是介面注入來產生依賴class的instance
:::success
需要的 遊戲,不用自己 下載,而是 網咖提供 給你。
----------------------||---------------------
需要的 物件,不用自己 取得,而是 服務容器 提供 給你。
----------------------||---------------------
需要的 依賴實例,不用 主動 (Active) 建立,而是 被動 (Passive) 接收。
:::
參考資料:
控制反轉 (IoC) 與 依賴注入 (DI)
https://notfalse.net/3/ioc-di
@Repository
简化 Spring 的开发。@Repository注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO类上即可。
@Service、@Controller 和 @Component 將class標示为Bean
- @Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
- @Service 通常作用在業務邏輯層,但是目前该功能与 @Component 相同。
- @Controller 通常作用在控制層(Controller),但是目前该功能與@Component 相同。
@PostConstruct
被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,並且只會被服務器執行一次。
@Transactional
假若你在class中設定了@Transactional, 該class所有的method有使用到JPA的都會被spring的transaction所管理。
舉例:當有個Transaction有三個動作:entity1.save, entity2.save, entity3.save.
若entity3.save失敗,那Spring就會將entity1.save與entity2.save的執行結果給rollback,還原其動作。
參考資料
https://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background
AOP相關的Annotaion
@Aspect
@Aspect:定義AOP,作用在class
AOP為 Aspect Oritented Programming
AOP通過給程序定義一個切入點,然後在其前後切入不同的執行內容
AOP不會破壞原來的程序邏輯
AOP使用場景:
- 紀錄日誌
- 事務管理
- 安全檢查
- 資源控制
@Pointcut, @Before, @After
範例
1 |
|
其他Annotation
@Cache
定義cache策略與範圍,可以定義以下參數:
-
usage: 當前緩存策略(NONE, READ_ONLY, NONSTRICT_READ_WRITE, TRANSACTIONAL)
- read-only: 只讀緩存
- 如果你的應用程序只需讀取一個持久化類的實例,而無需對其修改, 那麼就可以對其進行只讀緩存
- read-write: 讀寫緩存
- 如果應用程序需要更新數據,那麼使用讀/寫緩存比較合適。如果應用程序要求“序列化事務”的隔離級別(serializable transaction isolation level),那麼就決不能使用這種緩存策略
- nonstrict-read-write: 不嚴格讀寫緩存
- 如果應用程序只偶爾需要更新數據(也就是說,兩個事務同時更新同一記錄的情況很不常見),也不需要十分嚴格的事務隔離,那麼比較適合使用非嚴格讀/寫緩存策略。
- transactional :事務性緩存
- Hibernate 的事務緩存策略提供了全事務的緩存支持,例如對 JBoss TreeCache 的支持。這樣的緩存只能用於 JTA 環境中,你必須指定為其hibernate.transaction.manager_lookup_class屬性。
- read-only: 只讀緩存
-
region: 可選參數,指定二級緩存的去域名,默認為類或者集合的名字。
-
include: 可選參數(all, non-lazy)。 all包含所有屬性,non-lazy僅包含非延遲加載的屬性。
範例
1 | @Table(name = "PROVICE") |
1 | @Table(name = "PROVICE") |
參考資料
Hibernate @Cache注解-天才小小布
https://blog.csdn.net/w410589502/article/details/54603265
@Configuration
@Configuration的作用同以前的xml配置檔(例如Spring的applicationContext.xml或dispatcher-servlet.xml),用來設定Spring環境配置,例如宣告及註冊bean至Spring容器中,注入properties參數等。
範例
例如我們有一個FooService類別,若此類別要成為Spring容器管理的bean,有兩種方法:
- 一般在該類別上宣告@Component並搭配@ComponentScan掃描的方式註冊為bean
- 透過在@Configuration類別中搭配@Bean的方式註冊。
例如建立一個AppConfig並在類別名稱前掛上@Configuration,則此類別及成為Spring的配置類。在配置類的方法前掛上@Bean則方法回傳的物件就會被註冊為Spring容器管理的bean
fooService()方法便會將FooService註冊為bean。
1 | package com.will.advanced.demo.config; |
為了程式管理及維護上的方便,通常我們會把某些相關的配置寫在另外的配置檔,而不是全部塞在同一個類別,此時就可以利用@Configuration另外定義一個配置檔,例如上面的AppConfig。
@SpringBootApplication: 本身也包含@Configuration
而在Spring Boot中,@SpringBootApplication類本身即包含了@Configuration,所以可以直接在裡面進行如上Bean的配置,例如
1 | package com.will.advanced.demo; |
參考資料
Spring @Configuration作用
https://matthung0807.blogspot.com/2019/04/spring-configuration_28.html
@SpringBootApplication
定義 @SpringBootApplication的預設掃瞄bean的範圍
Spring Boot的@SpringBootApplication預設只會掃描所屬package下的類,因此若@Configuration類別定義在@SpringBootApplication類以外的package,則要用scanBasePackages屬性來設定要額外掃描的package,例如@SpringBootApplication(scanBasePackages=“com.will.advanced.demo.config”) (@Configuration包含了@Component),
1 | package com.will.advanced.demo; |
@Import
或是透過@Import來引入 ,例如
1 | package com.will.advanced.demo; |
:::warning
注意使用@Import會忽略@Configuration設定
:::
@Autowired
依賴注入物件
Spring的@Autowired用來依賴注入物件,典型的用法就是掛在類別成員變數上。@Autowired預設會依注入對象的類別型態來選擇容器(透過@Configuration定義的class會成為容器)中相符的物件(設置成bean)來注入。
1 |
|
Spring會自動去容器中找到 有容器定義CarBeans的bean
1 | import ....xxx.Car; |
@Autowire為Spring IoC的實現,不用自己去new一個car出來,而是透過容器(會做constructor or setter or interface injection),來去實現外部注入,降低模組(class)之間的耦合性
@EnableScheduling
若開發者在AppConfig類中使用了@EnableScheduling,並在某個task class中使用了@Schedule註解,那麼被@Schedule標註的方法既可以在指定時間內自動執行
注意:@EnableScheduling要與@Schedule搭配使用才有效果
@ConfigurationProperties
若想要把配置文件的信息,讀取好並自動封裝(getter讀取private的config值)成實體類,如此一來我們在代碼裡面使用就輕鬆許多,這時就可以使用@ConfiguationProperties,把同類的配置訊息自動封裝成實體類。
假設有設定文件在 application.properties
之下:
1 | connection.username=admin |
我們可以定義一個實體類在裝載配置文件信息
1 |
|
亦可以把 @ConfigurationProperties 定義在@Bean之下,說明@Bean是參考到有用configuationProperties設定的class
1 |
|
需要使用時直接用@Autowire注入
1 |
|
參考資料:
spring boot 使用@ConfigurationProperties
https://blog.csdn.net/yingxiake/article/details/51263071
@ConditionalOnClass
是Springboot实现自动配置的重要支撑之一。其用途是判断当前classpath下是否存在指定类,若是则将当前的配置装载入spring容器。
參考資料:
@ConditionalOnClass的使用探索 新日暮里格斗大会
https://blog.csdn.net/lucyTheSlayer/article/details/80430912
@ConditionalOnMissingBean
结合使用注解@ConditionalOnMissingBean和@Bean,可以做到只有特定名称或者类型的Bean不存在于BeanFactory中时才创建某个Bean
1 |
|
參考資料:
Spring Boot基于特定条件创建Bean例子 : ConditionalOnMissingBeanhttps:
//blog.csdn.net/andy_zhang2007/article/details/81285130