注解是個好東西,但好東西我們也是看見過,整理過,理解過,用過才知道好。不求我們每個都記住,但求保有印象,在需要的時候能提取出來再查找相關資料,平時工作就不會顯得那么被動了。 1.@Configuration注解 該類等價 與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里配置。
2.@Value注解 為了簡化從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:最小的線程數,缺?。? max size:最大的線程數,缺?。篒nteger.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(缺?。簰伋鯰askRejectedException異常,然后不執行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;
- }
- }
10.@Named @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 只要在類上加上這個注解,就可以實現一個單例類,不需要自己手動編寫單例實現類。
13.@Valid,@Valided @Valid 網上一大片使用@Valid失效不能用的情況。為什么呢? 1.@Valid必需使用在以@RequestBody接收參數的情況下。 2.使用ajax以POST方式提示數據,禁止用Fiddler以及瀏覽器直接訪問的方式測試接口 3.用<mvc:annotation-driven />添加注解驅動。 4.@Valid是應用在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 6.@Valid下后面緊跟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切面編程方式),如果參數非法即刻給前臺返回錯誤數據。 測試:http://127.0.0.1:8080/TestValidate/test/testValidated?pk=2&age=12 返回: 
注意 @Valid是使用hibernateValidation.jar做校驗 @Validated是只用springValidator校驗機制使用 gitHub下載地址
@Validated與@RequestBody結合使用時,在接口方法里要增加@Valid。例如:
- public Object edit(@Valid @RequestBody AddrRo addrRo) {.....}
14.@RequestBody @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模擬,不然會出錯。
15.@CrossOrigin 是Cross-Origin ResourceSharing(跨域資源共享)的簡寫 作用是解決跨域訪問的問題,在Spring4.2以上的版本可直接使用。在類上或方法上添加該注解 例如: - @CrossOrigin
- public class TestController extends BaseController {
-
- XXXX
-
- }
如果失效則可能方法沒解決是GET還是POST方式,指定即可解決問題。
將請求中參數為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/")
- 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
18.@Scope 配置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:作用不大,可不用管他。
19.@ResponseStatus @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 21.@ControllerAdvice 官方解釋是: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里可通過反射得到。
23.@RequestMapping 處理映射請求的注解。用于類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。有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提供的注解: 
下篇文章會研究自定義注解,自己動手試試注解的魅力。
|