基于注解的Controller
Request Mapping
消費(fèi)資源類型的請(qǐng)求
public void addPet(@RequestBody Pet pet) {
// ...
}
其中的"application/json"在MediaType中可以找到:APPLICATION_JSON_VALUE and APPLICATION_XML_VALUE</pre>
生產(chǎn)者類型的請(qǐng)求
@GetMapping(path = "/pets/{petId}", produces = "application/json;charset=UTF-8")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
"application/json;charset=UTF-8"在MediaType可以找到: APPLICATION_JSON_UTF8_VALUE, APPLICATION_XML_VALUE.</pre>
請(qǐng)求URL中加參數(shù)或者頭部加參數(shù)
匹配的路徑: /pet/pet?myParam=myValue
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
public void findPet(@PathVariable String petId) {
// ...
}
匹配的路徑: 必須在頭部消息中包含 myHeader=myValue
@GetMapping(path = "/pets", headers = "myHeader=myValue")
public void findPet(@PathVariable String petId) {
// ...
}
明確的注冊(cè)
可以動(dòng)態(tài)的注冊(cè)處理URL請(qǐng)求的方法,這種可以用在很高端的地方,例如:不同的實(shí)例請(qǐng)求不同的URL,但是這些 URL處理方法都一樣,這時(shí)候就可以這樣子做:
@Configuration
public class MyConfig {
?
@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler)
throws NoSuchMethodException {
?
RequestMappingInfo info = RequestMappingInfo
.paths("/user/{id}").methods(RequestMethod.GET).build();
?
Method method = UserHandler.class.getMethod("getUser", Long.class);
?
mapping.registerMapping(info, handler, method);
}
?
}
Handler Methods
方法的參數(shù)
| Controller方法參數(shù) | 描述 |
|---|---|
| ServerWebExchange | 可以理解為應(yīng)用上下文,可以得到request,response,session等 |
| ServletHttpRequest | request |
| ServletHttpResponse | response |
| WebSession | 可以得到session |
| HttpMethod | 得到請(qǐng)求的方法 |
| Locale | 可以得到請(qǐng)求的語(yǔ)言環(huán)境 |
| @PathVariable | 得到url模板參數(shù) |
| @RequestParam | 得到url請(qǐng)求的參數(shù) |
| @RequestHeader | 得到請(qǐng)求頭 |
| @CookieValue | 得到Cookie |
| @RequestBody | 得到HTTP請(qǐng)求的請(qǐng)求體的信息 |
| HttpEntity<B> | 得到請(qǐng)求頭和請(qǐng)求體的集合 |
| @RequestPart | 得到表單數(shù)據(jù) |
java.util.Map, org.springframework.ui.Model, and org.springframework.ui.ModelMap. |
用于訪問HTML控制器中使用的模型 |
| @ModelAttribute | 獲取模型中的參數(shù) |
| Errors,BindingResult | 得到驗(yàn)證和數(shù)據(jù)綁定的錯(cuò)誤信息 |
SessionStatus+ class-level@SessionAttributes |
不怎么明白 |
| UriComponentBuilder | 構(gòu)建請(qǐng)求URL |
@SessionAttribute |
目前 |
| @RequestAttribute | 訪問請(qǐng)求參數(shù) |
| 其他任何的參數(shù) | 如果是簡(jiǎn)單類型,默認(rèn)會(huì)被認(rèn)為是@RequestParam參數(shù) |
返回值
| 返回值 | 描述 |
|---|---|
| @ResponseBody | 返回值通過(guò)HttpMessageWriter實(shí)例寫入響應(yīng),其實(shí)就是返回 |
| HttpEntity OR ResponseEntity | 這個(gè)可以指定請(qǐng)求頭和請(qǐng)求體,very 強(qiáng)大 |
| HttpHeaders | 返回只有請(qǐng)求頭,沒有請(qǐng)求體 |
| String | 返回可以由ViewResolver解析的視圖名稱 |
| View | 返回某個(gè)動(dòng)態(tài)頁(yè)面文件 |
java.util.Map,org.springframework.ui.Model |
添加各種參數(shù)到隱式對(duì)象中,相當(dāng)于request.setAttribute |
| @ModelAttribute | 模型參數(shù) |
| void | 根據(jù)請(qǐng)求的url返回視圖 |
| Rendering | 不清楚 |
Flux<ServerSentEvent>, Observable<ServerSentEvent>, or other reactive type |
暫時(shí)沒見過(guò) ?? |
| 其他返回類型 | 作為視圖名處理 |
類型轉(zhuǎn)換
對(duì)于一些基于注解的controller方法參數(shù): @RequestParam,@PathVariable等,可能需要進(jìn)行類型轉(zhuǎn)換,他們默認(rèn)的類型是String類型,對(duì)于簡(jiǎn)單的類型轉(zhuǎn)換,如由String轉(zhuǎn)換成int ,long等,Sping自動(dòng)就轉(zhuǎn)換了,對(duì)于其他的可以參考Spring FIeld Formatting
矩陣變量
Spring默認(rèn)沒有開啟矩陣變量這種寫法,需要進(jìn)行配置
package com.yoke.lab.springbootlab.config;
?
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.util.UrlPathHelper;
?
/**
* @Author Yoke
* @Date 2019/01/14 上午10:39
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
?
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUrlPathHelper(urlPathHelper());
}
?
@Bean
public UrlPathHelper urlPathHelper() {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
return urlPathHelper;
}
}
- 最簡(jiǎn)單的矩陣變量
類似于普通的查詢參數(shù),矩陣變量也需要一個(gè)類似于占位符的東西,去表示 它
// GET /pets/42;q=11;r=22
?
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
?
// petId == 42
// q == 11
}
- 所有的路徑段可能全都包含矩陣變量,有時(shí)候需要區(qū)分矩陣變量
// GET /owners/42;q=11/pets/21;q=22
?
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
?
// q1 == 11
// q2 == 22
}
- 可以給矩陣變量設(shè)置為option和一個(gè)默認(rèn)值
// GET /pets/42
?
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
?
// q == 1
}
- 得到所有的矩陣變量
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
?
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap<String, String> matrixVars,
@MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {
?
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
@ReuqestParam
可以獲取請(qǐng)求參數(shù)
@Controller
@RequestMapping("/pets")
public class EditPetForm {
?
// ...
?
@GetMapping
public String setupForm(@RequestParam("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
?
// ...
?
}
Servlet API 中請(qǐng)求參數(shù)的概念包含了查詢參數(shù),表單數(shù)據(jù),和multipart的數(shù)據(jù),在WebFlux中這些數(shù)據(jù)都可以通過(guò)ServletWebExchange獲取,@ReuqestParam默認(rèn)只綁定了查詢參數(shù)
@RequestParam還可以用來(lái)加在Map<String, String> or MultiValueMap<String, String>上,這樣可以得到所有的查詢參數(shù)
@RequestParam注解使用后,后邊參數(shù)的類型就不會(huì)被其他參數(shù)解析器去解析,說(shuō)白了就是它后邊智能加常見的基本類型,不能加自定義的Java Bean
@Requestheader
獲取請(qǐng)求頭信息
例如:
Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300</pre>
可以指定得到哪些請(qǐng)求頭
下面這個(gè)例子: 得到Accept-Encoding和Keep-Alive的頭信息
@GetMapping("/demo")
public void handle(
@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
獲取全部的頭信息
可以把@RequestHeader加在Map<String, String>, MultiValueMap<String, String或者HttpHeaders參數(shù)上,這樣可以得到
Spring內(nèi)置支持將一個(gè)由
,分割的字符串,轉(zhuǎn)變成字符串?dāng)?shù)據(jù)或者集合,例如: @RequestHeader("Accept" 返回的結(jié)果可能是String但是也可能是String[],List<String>
@CookieValue
獲取Cookie信息
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}
@ModelAttribute
可以將請(qǐng)求的參數(shù),進(jìn)行數(shù)據(jù)綁定成一個(gè)Java Bean
模型參數(shù)包含請(qǐng)求的查詢參數(shù)和與字段名相同的表單字段信息,然后進(jìn)行封裝,這就是數(shù)據(jù)綁定WebExchangeDataBinder會(huì)進(jìn)行查詢參數(shù),表單字段與聲明的字段信息進(jìn)行匹配,封裝成想要的Java Bean
package com.yoke.lab.springbootlab.web;
?
import com.yoke.lab.springbootlab.pojo.User;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
?
/**
* @Author Yoke
* @Date 2019/01/14 上午9:36
*/
@RestController
@RequestMapping(path = "/")
public class IndexController {
?
?
@PostMapping("/index/{id}/{name}/{pwd}")
public String findPet(@ModelAttribute User user) {
System.out.println(user);
return "aaa";
}
?
}
數(shù)據(jù)綁定可能出錯(cuò),可以通過(guò)使用BindingResult來(lái)對(duì)可能出現(xiàn)的異常進(jìn)行處理
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
還可以在數(shù)據(jù)綁定之后加入驗(yàn)證javax.validation.Valid,Spring的@Validated注解
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
在SpringWebFlux中,支持響應(yīng)式的模型,不能再@ModelAttribute之前申明任何一個(gè)響應(yīng)式的模型,響應(yīng)式可以這樣子處理錯(cuò)誤
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public Mono<String> processSubmit(@Valid @ModelAttribute("pet") Mono<Pet> petMono) {
return petMono
.flatMap(pet -> {
// ...
})
.onErrorResume(ex -> {
// ...
});
}
@SessionAttributes
@SessionAttributes用來(lái)將請(qǐng)求之間的模型數(shù)據(jù)存儲(chǔ)到WebSession中,它是一個(gè)類層級(jí)的注解
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
當(dāng)一個(gè)請(qǐng)求,帶有pet的模型參數(shù)時(shí),它的數(shù)據(jù)就會(huì)被自動(dòng)存儲(chǔ)到WebSession中,直到一個(gè)Controlelr方法使用SessionStatus為參數(shù)進(jìn)行清除存儲(chǔ)
@Controller
@SessionAttributes("pet")
public class EditPetForm {
?
// ...
?
@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
}
@SessionAttribute
可以訪問全局的已經(jīng)存在的session
@GetMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}
如果想要添加或者刪除全局的session,可以在controller中注入WbbSession
@RequestAttribute
與@SessionAttribute類似,它可以獲取已經(jīng)存在的請(qǐng)求參數(shù)
Multipart Content
我沒用過(guò)??
@RequestBody
讀請(qǐng)求體的內(nèi)容,通過(guò)HttpMessageReader反序列化為對(duì)象
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
與Spring MVC不同的是,注解參數(shù)支持響應(yīng)式類型
@PostMapping("/accounts")
public void handle(@RequestBody Mono<Account> account) {
// ...
}
這個(gè)可以結(jié)合javax.validation.Valid,Spring的@Validated使用,默認(rèn)情況下,驗(yàn)證錯(cuò)誤將會(huì)引起WebExchangeBindException會(huì)出現(xiàn)400(BAD_REQUEST),我們可以使用Errorsor BindingResult參數(shù)來(lái)處理錯(cuò)誤
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
// ...
}
HttpEntity
或多或少等同于@RequestBody,它包含了request暴露出來(lái)的請(qǐng)求頭和請(qǐng)求體
@ResponseBody
將返回的信息序列化使用HttpMessageWriter到請(qǐng)求體中
@ResponseBody支持方法級(jí)別,也支持類級(jí)別
ResponseEntity
包含了請(qǐng)求的頭,體,狀態(tài)碼,三種信息
Jackson JSON
Spring WebFlux提供了Jackson JSON(支持序列化)
管理異常
對(duì)于一個(gè)REST 服務(wù)來(lái)說(shuō),通常需要將錯(cuò)誤信息展示在請(qǐng)求體中,Spring沒有自動(dòng)實(shí)現(xiàn),因?yàn)轫憫?yīng)正文中的錯(cuò)誤是針對(duì)特定的應(yīng)用的。我們可以在@RestController類中,寫一個(gè)@ExceptionHanlder注解的方法,用ResponseENtity作為返回值,去設(shè)置返回的各種信息。也可以將這種方法寫在@ControllerAdvice注解的類中,用于全局
Controller Advice
對(duì)于一些全局的操作可以放在這里,常用的就是異常處理了
默認(rèn),每次請(qǐng)求,都會(huì)經(jīng)過(guò)這里,但是可以通過(guò)注解的一些參數(shù)來(lái)限制
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
?
// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
?
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
Example
package com.yoke.lab.springbootlab.config;
?
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
?
/**
* @Author Yoke
* @Date 2019/01/15 上午10:43
*/
@ControllerAdvice
public class Advice {
?
@ExceptionHandler
public ResponseEntity<String> response(Exception e) {
System.out.println(e.getMessage());
System.out.println("handle");
return new ResponseEntity<>("error", new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
}
package com.yoke.lab.springbootlab.web;
?
import com.yoke.lab.springbootlab.pojo.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
?
/**
* @Author Yoke
* @Date 2019/01/14 上午9:36
*/
@RestController
@RequestMapping(path = "/")
public class IndexController {
?
?
@ModelAttribute
@GetMapping(path = "/test")
public User getUser() {
int i = 10 / 0;
return new User(1, "sd", "ds");
}
}
result
/ by zero
handle
/ by zero
handle
/ by zero
handle
瀏覽器的結(jié)果自然就是設(shè)定的ResponseEntity