WebFlux-Annotated Controllers

基于注解的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;
 }
}
  1. 最簡(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
}
  1. 所有的路徑段可能全都包含矩陣變量,有時(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
}
  1. 可以給矩陣變量設(shè)置為option和一個(gè)默認(rèn)值
// GET /pets/42
?
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
?
 // q == 1
}
  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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容