Spring Annotations

Spring Annotations

1. @Configuration

​ 等價與XML中配置beans,至關於Ioc容器,它的某個方法頭上若是註冊了@Bean,就會做爲這個Spring容器中的Bean,與xml中配置的bean意思同樣。html

​ @Configuration註解的類必需使用<context:component-scan base-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-scan base-package=」XXX」/>掃描該類,最終咱們能夠在程序裏用@AutoWired或@Resource註解取得用@Bean註解的bean,和用xml先配置bean而後在程序裏自動注入同樣,目的是減小xml裏配置。java

2. @Value

​ 爲了簡化從properties裏取配置,可使用@Value, 能夠properties文件中的配置值。git

在dispatcher-servlet.xml裏引入properties文件。程序員

<context:property-placeholder location="classpath:test.properties" />

在程序裏使用@Value:web

@Value("${wx_appid}")

publicString appid;

即便給變量賦了初值也會以配置文件的值爲準。ajax

3. @Controller, @Service, @Repository,@Component

`目前4種註解意思是同樣,並無什麼區別,區別只是名字不一樣。使用方法:正則表達式

  1. 使用<context:component-scan base-package="XXX"/>掃描被註解的類
  2. 在類上寫註解
@Controller

public class TestController {

}

4. @PostConstruct 和 @PreDestory

實現初始化和銷燬bean以前進行的操做,只能有一個方法能夠用此註釋進行註釋,方法不能有參數,返回值必需是void,方法須要是非靜態的spring

例如:sql

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) {
        // 建立MyCallable對象
        Callable<Integer> myCallable = new MyCallable();    
        // 使用FutureTask來包裝MyCallable對象
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); 
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                // FutureTask對象做爲Thread對象的target建立新的線程
                Thread thread = new Thread(ft);   
                // 線程進入到就緒狀態
                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形式的配置:

1.第一步配置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」/>

配置參數

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:不在新線程中執行任務,而是有調用者所在的線程來執行

2.第二步在類或方法上添加@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. 添加註解驅動。

  4. @Valid是應用在javabean上的校驗

<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)長度是否在給定的範圍以內
@AssertFalse 驗證註解的元素值長度在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之間
@Valid 遞歸的對關聯對象進行校驗, 若是關聯對象是個集合或者數組,那麼對其中的元素進行遞歸校驗,若是是一個map,則對其中的值部分進行校驗.(是否進行遞歸驗證)
@CreditCardNumber 信用卡驗證
@Email 驗證是不是郵件地址,若是爲null,不進行驗證,算經過驗證
@ScriptAssert(lang=,script=, alias=)
@URL(protocol=,host=,port=,regexp=, flags=)
@Range(min=10000,max=50000,message="range.bean.wage")

private BigDecimal wage;

@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是使用hibernate Validation.jar作校驗
  • @Validated是隻用spring Validator校驗機制使用

@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 {
 
}

若是失效則可能方法沒解決是GET仍是POST方式,指定便可解決問題

16. @RequestParam

做用是提取和解析請求中的參數。

@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

@SessionAttributes,@ModelAttribute:處理attribute類型註解

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內有效
session 同一個session共享一個bean,不一樣的session使用不一樣的bean

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{

}

當某處拋出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 {

}

@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) {
    
}

value的uri值爲如下三類:

  1. 能夠指定爲普通的具體值;如@RequestMapping(value ="/testValid")
  2. 能夠指定爲含有某變量的一類值;如@RequestMapping(value="/{day}")
  3. 能夠指定爲含正則表達式的一類值;如@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)

相關文章
相關標籤/搜索