史上最全的java spring註解,沒有之一
註解是個好東西,但好東西我們也是看見過,整理過,理解過,用過才知道好。不求我們每個都記住,但求保有印象,在需要的時候能提取出來再查詢相關資料,平時工作就不會顯得那麼被動了。
該類等價 與XML中配置beans,相當於Ioc容器,它的某個方法頭上如果註冊了@Bean,就會作為這個Spring容器中的Bean,與xml中配置的bean意思一樣。
@Configuration註解的類必需使用<context:component-scanbase-package="XXX"/>掃描.如下:
@Configuration public class MainConfig { //在properties檔案裡配置 @Value("${wx_appid}") public String appid; protected MainConfig(){} @Bean public WxMpService wxMpService() { WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); return wxMpService; } }
定義一個MainConfig,用@Configuration註解,那MainConfig相當於xml裡的beans,裡面用@Bean註解的和xml裡定義的bean等價,用<context:component-scanbase-package=”XXX”/>掃描該類,最終我們可以在程式裡用@AutoWired或@Resource註解取得用@Bean註解的bean,和用xml先配置bean然後在程式裡自動注入一樣。目的是減少xml裡配置。
為了簡化從properties裡取配置,可以使用@Value, 可以properties檔案中的配置值。
在dispatcher-servlet.xml裡引入properties檔案。
<context:property-placeholder location="classpath:test.properties" />
在程式裡使用@Value:
@Value("${wx_appid}")
publicString appid;即使給變數賦了初值也會以配置檔案的值為準。
3. @Controller, @Service, @Repository,@Component
目前4種註解意思是一樣,並沒有什麼區別,區別只是名字不同。使用方法:
1.使用<context:component-scanbase-package="XXX"/>掃描被註解的類
2. 在類上寫註解:
@Controller
public class TestController {
}
4. @PostConstruct 和 @PreDestory
實現初始化和銷燬bean之前進行的操作,只能有一個方法可以用此註釋進行註釋,方法不能有引數,返回值必需是void,方法需要是非靜態的。
例如:public class TestService {
@PostConstruct
public void init(){
System.out.println("初始化");
}
@PreDestroy
public void dostory(){
System.out.println("銷燬");
}
}
@PostConstruct:在構造方法和init方法(如果有的話)之間得到呼叫,且只會執行一次。
@PreDestory:註解的方法在destory()方法呼叫後得到執行。
網上拷貝的流程圖:
引深一點,Spring 容器中的 Bean 是有生命週期的,Spring 允許在 Bean 在初始化完成後以及 Bean 銷燬前執行特定的操作,常用的設定方式有以下三種:
1.通過實現 InitializingBean/DisposableBean 介面來定製初始化之後/銷燬之前的操作方法;
2.通過 <bean> 元素的 init-method/destroy-method屬性指定初始化之後 /銷燬之前呼叫的操作方法;
3.在指定方法上加上@PostConstruct 或@PreDestroy註解來制定該方法是在初始化之後還是銷燬之前呼叫
但他們之前並不等價。即使3個方法都用上了,也有先後順序.
Constructor > @PostConstruct >InitializingBean > init-method
5. @Primary
自動裝配時當出現多個Bean候選者時,被註解為@Primary的Bean將作為首選者,否則將丟擲異常。
例如:
@Component
public class Apple implements Fruit{
@Override
public String hello() {
return "我是蘋果";
}
}
@Component
@Primary
public class Pear implements Fruit{
@Override
public String hello(String lyrics) {
return "梨子";
}
}
public class FruitService {
//Fruit有2個例項子類,因為梨子用@Primary,那麼會使用Pear注入
@Autowired
private Fruit fruit;
public String hello(){
return fruit.hello();
}
}
6. @Lazy(true)
用於指定該Bean是否取消預初始化,用於註解類,延遲初始化。
7. @Autowired
Autowired預設先按byType,如果發現找到多個bean,則,又按照byName方式比對,如果還有多個,則報出異常。
1.可以手動指定按byName方式注入,使用@Qualifier。
//通過此註解完成從spring配置檔案中 查詢滿足Fruit的bean,然後按//@Qualifier指定pean
@Autowired
@Qualifier("pean")
public Fruit fruit;
2.如果要允許null 值,可以設定它的required屬性為false,如:@Autowired(required=false)
public Fruit fruit;
8. @Resource
預設按 byName自動注入,如果找不到再按byType找bean,如果還是找不到則拋異常,無論按byName還是byType如果找到多個,則拋異常。
可以手動指定bean,它有2個屬性分別是name和type,使用name屬性,則使用byName的自動注入,而使用type屬性時則使用byType自動注入。
@Resource(name=”bean名字”)
或
@Resource(type=”bean的class”)
這個註解是屬於J2EE的,減少了與spring的耦合。
9. @Async
java裡使用執行緒用3種方法:
1. 繼承Thread,重寫run方法
2. 實現Runnable,重寫run方法
3. 使用Callable和Future介面建立執行緒,並能得到返回值。
前2種簡單,第3種方式特別提示一下,例子如下:
class MyCallable implements Callable<Integer> {
private int i = 0;
// 與run()方法不同的是,call()方法具有返回值
@Override
public Integer call() {
int sum = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}
}
main方法:
public static void main(String[] args) {
Callable<Integer> myCallable = new MyCallable(); // 建立MyCallable物件
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable物件
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
Thread thread = new Thread(ft); //FutureTask物件作為Thread物件的target建立新的執行緒
thread.start(); //執行緒進入到就緒狀態
}
}
System.out.println("主執行緒for迴圈執行完畢..");
try {
int sum = ft.get(); //取得新建立的新執行緒中的call()方法返回的結果
System.out.println("sum = " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
而使用@Async可視為第4種方法。基於@Async標註的方法,稱之為非同步方法,這個註解用於標註某個方法或某個類裡面的所有方法都是需要非同步處理的。被註解的方法被呼叫的時候,會在新執行緒中執行,而呼叫它的方法會在原來的執行緒中執行。
application.xml形勢的配置:
第一步配置XML。
<!--掃描註解,其中包括@Async -->
<context:component-scan base-package="com.test"/>
<!-- 支援非同步方法執行, 指定一個預設的executor給@Async使用-->
<task:annotation-driven executor="defaultAsyncExecutor" />
<!—配置一個執行緒執行器-->
<task:executor id=" defaultAsyncExecutor "pool-size="100-10000" queue-capacity="10" keep-alive =”5”/>
引數解讀:
<task:executor />配置引數:
id:當配置多個executor時,被@Async("id")指定使用;也被作為執行緒名的字首。
pool-size:
core size:最小的執行緒數,預設:1
max size:最大的執行緒數,預設:Integer.MAX_VALUE
queue-capacity:當最小的執行緒數已經被佔用滿後,新的任務會被放進queue裡面,當這個queue的capacity也被佔滿之後,pool裡面會建立新執行緒處理這個任務,直到匯流排程數達到了max size,這時系統會拒絕這個任務並丟擲TaskRejectedException異常(預設配置的情況下,可以通過rejection-policy來決定如何處理這種情況)。預設值為:Integer.MAX_VALUE
keep-alive:超過core size的那些執行緒,任務完成後,再經過這個時長(秒)會被結束掉
rejection-policy:當pool已經達到max size的時候,如何處理新任務
ABORT(預設):丟擲TaskRejectedException異常,然後不執行DISCARD:不執行,也不丟擲異常
DISCARD_OLDEST:丟棄queue中最舊的那個任務
CALLER_RUNS:不在新執行緒中執行任務,而是有呼叫者所在的執行緒來執行
第二步在類或方法上新增@Async,當呼叫該方法時,則該方法即是用異常執行的方法單獨開個新執行緒執行。
@Async(“可以指定執行器id,也可以不指定”)
public static void testAsyncVoid (){
try {
//讓程式暫停100秒,相當於執行一個很耗時的任務
System.out.println(“異常執行列印字串”);
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
當在外部呼叫testAsync方法時即在新執行緒中執行,由上面<task: annotation-driven/>執行器去維護執行緒。
總結:先用context:component-scan去掃描註解,讓spring能識別到@Async註解,然後task:annotation-driven去驅動@Async註解,並可以指定預設的執行緒執行器executor。那麼當用@Async註解的方法或類得到呼叫時,執行緒執行器會建立新的執行緒去執行。
上面方法是無返回值的情況,還有異常方法有返回值的例子。
@Async
public Future<String> testAsyncReturn () {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
返回的資料型別為Future型別,介面實現類是AsyncResult.
呼叫方法如下:
public void test(){
Future<String> future = cc.testAsyncReturn();
while (true) { ///這裡使用了迴圈判斷,等待獲取結果資訊
if (future.isDone()) { //判斷是否執行完畢
System.out.println("Result from asynchronous process - " + future.get());
break;
}
System.out.println("Continue doing something else. ");
Thread.sleep(1000);
}
}
通過不停的檢查Future的狀態來獲取當前的非同步方法是否執行完畢
參考文章程式設計的方式使用@Async:
@Configuration
@EnableAsync
public class SpringConfig {
private int corePoolSize = 10;
private int maxPoolSize = 200;
private int queueCapacity = 10;
private String ThreadNamePrefix = "MyLogExecutor-";
@Bean
public Executor logExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(ThreadNamePrefix);
// rejection-policy:當pool已經達到max size的時候,如何處理新任務
// CALLER_RUNS:不在新執行緒中執行任務,而是有呼叫者所在的執行緒來執行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
@Named和Spring的@Component功能相同。@Named可以有值,如果沒有值生成的Bean名稱預設和類名相同。比如
@Named public class Person
或
@Named("cc") public class Person
11. @Inject
使用@Inject需要引用javax.inject.jar,它與Spring沒有關係,是jsr330規範。
與@Autowired有互換性。
12. @Singleton
只要在類上加上這個註解,就可以實現一個單例類,不需要自己手動編寫單例實現類。
@Valid
網上一大片使用@Valid失效不能用的情況。為什麼呢?
[email protected]必需使用在以@RequestBody接收引數的情況下。
2.使用ajax以POST方式提示資料,禁止用Fiddler以及瀏覽器直接訪問的方式測試介面
3.用<mvc:annotation-driven />添加註解驅動。
[email protected]是應用在javabean上的校驗。
5.<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.5.3</version>
這些jar包是需要的。@Valid是使用hibernate validation的時候使用,可引數下面介紹的@RequestBody
[email protected]下後面緊跟BindingResult result,驗證結果儲存在result
例如:
@RequestMapping("/test")
public String testValid(@Valid User user, BindingResult result){
if (result.hasErrors()){
List<ObjectError> errorList = result.getAllErrors();
for(ObjectError error : errorList){
System.out.println(error.getDefaultMessage());
}
}
return "test";
}
在入參User上添加了@Valid做校驗,在User類裡屬性上實行實際的特定校驗。
例如在User的name屬性上加
@NotBlank
private String name;
全部引數校驗如下:
空檢查
@Null 驗證物件是否為null
@NotNull 驗證物件是否不為null, 無法查檢長度為0的字串
@NotBlank 檢查約束字串是不是Null還有被Trim的長度是否大於0,只對字串,且會去掉前後空格.
@NotEmpty 檢查約束元素是否為NULL或者是EMPTY.
Booelan檢查
@AssertTrue 驗證 Boolean 物件是否為 true
@AssertFalse 驗證 Boolean 物件是否為 false
長度檢查
@Size(min=, max=) 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內
@Length(min=, max=)驗證註解的元素值長度在min和max區間內
日期檢查
@Past 驗證 Date 和 Calendar 物件是否在當前時間之前
@Future 驗證 Date 和 Calendar 物件是否在當前時間之後
@Pattern 驗證 String 物件是否符合正則表示式的規則
數值檢查,建議使用在Stirng,Integer型別,不建議使用在int型別上,因為表單值為“”時無法轉換為int,但可以轉換為Stirng為"",Integer為null
@Min(value=””) 驗證 Number 和 String 物件是否大等於指定的值
@Max(value=””) 驗證 Number 和 String 物件是否小等於指定的值
@DecimalMax(value=值) 被標註的值必須不大於約束中指定的最大值. 這個約束的引數是一個通過BigDecimal定義的最大值的字串表示.小數存在精度
@DecimalMin(value=值) 被標註的值必須不小於約束中指定的最小值. 這個約束的引數是一個通過BigDecimal定義的最小值的字串表示.小數存在精度
@Digits 驗證 Number 和 String 的構成是否合法
@Digits(integer=,fraction=)驗證字串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度。
@Range(min=, max=) 檢查數字是否介於min和max之間.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 遞迴的對關聯物件進行校驗, 如果關聯物件是個集合或者陣列,那麼對其中的元素進行遞迴校驗,如果是一個map,則對其中的值部分進行校驗.(是否進行遞迴驗證)
@CreditCardNumber信用卡驗證
@Email 驗證是否是郵件地址,如果為null,不進行驗證,算通過驗證。
@ScriptAssert(lang=,script=, alias=)
@URL(protocol=,host=,port=,regexp=, flags=)
@Validated
@Valid是對javabean的校驗,如果想對使用@RequestParam方式接收引數方式校驗使用@Validated
使用@Validated的步驟:
第一步:定義全域性異常,讓該全域性異常處理器能處理所以驗證失敗的情況,並返回給前臺失敗提示資料。如下,該類不用在任何xml裡配置。import javax.validation.ValidationException;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
@ExceptionHandler
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handle(ValidationException exception) {
System.out.println("bad request, " + exception.getMessage());
return "bad request, " + exception.getMessage();
}
}
第二步。在XXController.java頭上新增@Validated,然後在@RequestParam後臺使用上面介紹的驗證註解,比如@NotBlank,@Rank.
如下:
@Controller
@RequestMapping("/test")
@Validated
public class TestController extends BaseController {
@RequestMapping(value = "testValidated", method = RequestMethod.GET)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Object testValidated(@RequestParam(value = "pk", required = true) @Size(min = 1, max = 3) String pk,
@RequestParam(value = "age", required = false) @Range(min = 1, max = 3) String age) {
try {
return "pk:" + pk + ",age=" + age;
} catch (Throwable t) {
return buildFailure("訊息列表查詢失敗");
}
}
}
當入非法引數是,會被全域性處理器攔截到,(Spring切面程式設計方式),如果引數非法即刻給前臺返回錯誤資料。
返回:
注意
@Valid是使用hibernateValidation.jar做校驗
@Validated是隻用springValidator校驗機制使用
@Validated與@RequestBody結合使用時,在介面方法裡要增加@Valid。例如:
public Object edit(@Valid @RequestBody AddrRo addrRo) {.....}
@RequestBody(required=true)
:有個預設屬性required,預設是true,當body裡沒內容時拋異常。
application/x-www-form-urlencoded:窗體資料被編碼為名稱/值對。這是標準的編碼格式。這是預設的方式
multipart/form-data:窗體資料被編碼為一條訊息,頁上的每個控制元件對應訊息中的一個部分。二進位制資料傳輸方式,主要用於上傳檔案
注意:必需使用POST方式提交引數,需要使用ajax方式請求,用Fiddler去模擬post請求不能。
引用jar包:
Spring相關jar包。
以及
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
dispatchServlet-mvc.xml配置
第一種,直接配置MappingJackson2HttpMessageCoverter:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</property>
</bean>
第二種:<mvc:annotation-driven/> 就不用配置上面bean,預設會配好。
Ajax請求:
function testRequestBody() {
var o = {"status":9};
jQuery.ajax({
type: "POST",
url: "http://127.0.0.1:8080/TestValidate/test/testValid",
xhrFields:{
withCredentials:true
},
data: JSON.stringify(o),
contentType: "application/json",
dataType: "json",
async: false,
success:function (data) {
console.log(data);
},
error: function(res) {
console.log(res);
}
});
}
後臺XXXcontroller.java:
@RequestMapping(value="/ testValid ",method=RequestMethod.POST)
@ResponseBody
public Object setOrderInfo(@RequestBody InfoVO infoVO,HttpServletRequest request, HttpServletResponse response){
InfoVO cVo = getInfoVo(infoVO);
return "success";
}
開發時,不是報415,就是400錯誤,頭都大了。還是細節沒做到位,注意下面幾個要點:
Content-Type必需是application/json
需要jackson-databind.jar
<mvc:annotation-driven/>要配置或直接配置bean
XXXController.jar在post方式接收資料
最最重要的,使用ajax以post方式請求。不能用Fiddler模擬,不然會出錯。
是Cross-Origin ResourceSharing(跨域資源共享)的簡寫
作用是解決跨域訪問的問題,在Spring4.2以上的版本可直接使用。在類上或方法上新增該註解
例如:
@CrossOrigin
public class TestController extends BaseController {
XXXX
}
如果失效則可能方法沒解決是GET還是POST方式,指定即可解決問題。
作用是提取和解析請求中的引數。@RequestParam支援型別轉換,型別轉換目前支援所有的基本Java型別
@RequestParam([value="number"], [required=false]) String number
將請求中引數為number對映到方法的number上。required=false表示該引數不是必需的,請求上可帶可不帶。
17. @PathVariable,@RequestHeader,@CookieValue,@RequestParam, @RequestBody,@SessionAttributes, @ModelAttribute;
@PathVariable:處理requet uri部分,當使用@RequestMapping URI template 樣式對映時, 即someUrl/{paramId}, 這時的paramId可通過 @Pathvariable註解繫結它傳過來的值到方法的引數上
例如:
@Controller
@RequestMapping("/owners/{a}")
public class RelativePathUriTemplateController {
@RequestMapping("/pets/{b}")
public void findPet(@PathVariable("a") String a,@PathVariable String b, Model model) {
// implementation omitted
}
}
@RequestHeader,@CookieValue: 處理request header部分的註解
將頭部資訊繫結到方法引數上:
@RequestMapping("/test")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive")long keepAlive) {
//...
}
//將cookie裡JSESSIONID繫結到方法引數上
@RequestMapping("/test")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
//...
}
@RequestParam, @RequestBody: 處理request body部分的註解,已經介紹過,不用介紹了。
@SessionAttributes,@ModelAttribute:處理attribute型別是註解。XXXX
配置bean的作用域。
@Controller
@RequestMapping("/test")
@Scope("prototype")
public class TestController {
}
預設是單例模式,即@Scope("singleton"),
singleton:單例,即容器裡只有一個例項物件。
prototype:多物件,每一次請求都會產生一個新的bean例項,Spring不無法對一個prototype bean的整個生命週期負責,容器在初始化、配置、裝飾或者是裝配完一個prototype例項後,將它交給客戶端,由程式設計師負責銷燬該物件,不管何種作用域,容器都會呼叫所有物件的初始化生命週期回撥方法,而對prototype而言,任何配置好的析構生命週期回撥方法都將不會被呼叫
request:對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效
web.xml增加如下配置:<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
session:該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效。也要在web.xml配置如下程式碼:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
global session:作用不大,可不用管他。
@ResponseStatus用於修飾一個類或者一個方法,修飾一個類的時候,一般修飾的是一個異常類,當處理器的方法被呼叫時,@ResponseStatus指定的code和reason會被返回給前端。value屬性是http狀態碼,比如404,500等。reason是錯誤資訊
當修改類或方法時,只要該類得到呼叫,那麼value和reason都會被新增到response裡
例如:
@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="出現了錯誤")
public class UserException extends RuntimeException{
XXXXX
}
當某處丟擲UserException時,則會把value和reason返回給前端。
@RequestMapping("/testResponseStatus")
public String testResponseStatus(int i){
if(i==0)
throw new UserNotMatchException();
return "hello";
}
修改方法:
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
@ExceptionHandler
@ResponseBody
@ResponseStatus(value=HttpStatus.BAD_REQUEST,reason="哈哈")
public String handle(ValidationException exception) {
System.out.println("bad request, " + exception.getMessage());
return "bad request, " + exception.getMessage();
}
}
結果如下:
正如上面所說,該方法得到呼叫,不論是否拋異常,都會把value和reason新增到response裡。
總結:@ResponseStatus是為了在方法或類得到呼叫時將指定的code和reason新增到response裡返前端,就像伺服器常給我們報的404錯誤一樣,我們可以自己指定高逼格錯誤提示。
20. @RestController
@RestController = @Controller + @ResponseBody。
是2個註解的合併效果,即指定了該controller是元件,又指定方法返回的是String或json型別資料,不會解決成jsp頁面,註定不夠靈活,如果一個Controller即有SpringMVC返回檢視的方法,又有返回json資料的方法即使用@RestController太死板。
靈活的作法是:定義controller的時候,直接使用@Controller,如果需要返回json可以直接在方法中新增@ResponseBody
官方解釋是:It is typically used todefine@ExceptionHandler,
@InitBinder, and@ModelAttribute methods that apply to all@RequestMapping methods
意思是:即把@ControllerAdvice註解內部使用@ExceptionHandler、@InitBinder、@ModelAttribute註解的方法應用到所有的 @RequestMapping註解的方法。非常簡單,不過只有當使用@ExceptionHandler最有用,另外兩個用處不大。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SQLException.class)
@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR,reason=”sql查詢錯誤”)
@ResponseBody
public ExceptionResponse handleSQLException(HttpServletRequest request, Exception ex) {
String message = ex.getMessage();
return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
}
}
即表示讓Spring捕獲到所有丟擲的SQLException異常,並交由這個被註解的handleSQLException方法處理,同時使用@ResponseStatus指定了code和reason寫到response上,返回給前端。
22.元註解包括 @Retention @Target @Document @Inherited四種
元註解是指註解的註解,比如我們看到的ControllerAdvice註解定義如下。@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
XXX
}
@Retention: 定義註解的保留策略:
@Retention(RetentionPolicy.SOURCE) //註解僅存在於原始碼中,在class位元組碼檔案中不包含
@Retention(RetentionPolicy.CLASS) //預設的保留策略,註解會在class位元組碼檔案中存在,但執行時無法獲得,
@Retention(RetentionPolicy.RUNTIME) //註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到
@Target:定義註解的作用目標:
@Target(ElementType.TYPE) //介面、類、列舉、註解
@Target(ElementType.FIELD) //欄位、列舉的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER)//方法引數
@Target(ElementType.CONSTRUCTOR) //建構函式
@Target(ElementType.LOCAL_VARIABLE)//區域性變數
@Target(ElementType.ANNOTATION_TYPE)//註解
@Target(ElementType.PACKAGE) ///包
由以上的原始碼可以知道,他的elementType 可以有多個,一個註解可以為類的,方法的,欄位的等等
@Document:說明該註解將被包含在javadoc中
@Inherited:說明子類可以繼承父類中的該註解
比如@Valid註解定義是
表示該註解只能用在方法,屬性,建構函式及方法引數上。該注意會被編譯到class裡可通過反射得到。
處理對映請求的註解。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。有6個屬性。
1、 value, method:
value:指定請求的實際地址,指定的地址可以是URI Template 模式;
method:指定請求的method型別, GET、POST、PUT、DELETE等;
比如:
@RequestMapping(value = "/testValid", method = RequestMethod.POST)
@ResponseBody
public Object testValid(@RequestBody @Valid Test test,BindingResult result, HttpServletRequest request, HttpServletResponse response) {
XXX
}
value的uri值為以下三類:
A) 可以指定為普通的具體值;如@RequestMapping(value ="/testValid")
B) 可以指定為含有某變數的一類值;如@RequestMapping(value="/{day}")
C) 可以指定為含正則表示式的一類值;如@RequestMapping(value="/{textualPart:[a-z-]+}.{numericPart:[\\d]+}") 可以匹配../chenyuan122912請求。
2、 consumes,produces:
consumes: 指定處理請求的提交內容型別(Content-Type),例如@RequestMapping(value = "/test", consumes="application/json")處理application/json內容型別
produces: 指定返回的內容型別,僅當request請求頭中的(Accept)型別中包含該指定型別才返回;
3 params、headers:
params: 指定request中必須包含某些引數值是,才讓該方法處理。
例如:
@RequestMapping(value = "/test", method = RequestMethod.GET, params="name=chenyuan")
public void findOrd(String name) {
// implementation omitted
}
僅處理請求中包含了名為“name”,值為“chenyuan”的請求.
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求。
@RequestMapping(value = "/test", method = RequestMethod.GET, headers="Referer=www.baidu.com")
public void findOrd(String name) {
// implementation omitted
}
僅處理request的header中包含了指定“Refer”請求頭和對應值為“www.baidu.com”的請求
另贈spring提供的註解:
24. @GetMapping和@PostMapping
@GetMapping(value = "page")等價於@RequestMapping(value = "page", method = RequestMethod.GET)
@PostMapping(value = "page")等價於@RequestMapping(value = "page", method = RequestMethod.POST)
下篇文章會研究自定義註解,自己動手試試註解的魅力。