美文网首页
WebFlux-Annotated Controllers

WebFlux-Annotated Controllers

作者: Yoke_336e | 来源:发表于2019-01-15 11:58 被阅读0次

基于注解的Controller

Request Mapping

消费资源类型的请求

public void addPet(@RequestBody Pet pet) {
 // ...
}

其中的"application/json"在MediaType中可以找到:APPLICATION_JSON_VALUE and APPLICATION_XML_VALUE</pre>

生产者类型的请求

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

请求URL中加参数或者头部加参数

匹配的路径: /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) {
 // ...
}

明确的注册

可以动态的注册处理URL请求的方法,这种可以用在很高端的地方,例如:不同的实例请求不同的URL,但是这些 URL处理方法都一样,这时候就可以这样子做:

@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

方法的参数

Controller方法参数 描述
ServerWebExchange 可以理解为应用上下文,可以得到request,response,session等
ServletHttpRequest request
ServletHttpResponse response
WebSession 可以得到session
HttpMethod 得到请求的方法
Locale 可以得到请求的语言环境
@PathVariable 得到url模板参数
@RequestParam 得到url请求的参数
@RequestHeader 得到请求头
@CookieValue 得到Cookie
@RequestBody 得到HTTP请求的请求体的信息
HttpEntity<B> 得到请求头和请求体的集合
@RequestPart 得到表单数据
java.util.Map, org.springframework.ui.Model, and org.springframework.ui.ModelMap. 用于访问HTML控制器中使用的模型
@ModelAttribute 获取模型中的参数
Errors,BindingResult 得到验证和数据绑定的错误信息
SessionStatus+ class-level@SessionAttributes 不怎么明白
UriComponentBuilder 构建请求URL
@SessionAttribute 目前
@RequestAttribute 访问请求参数
其他任何的参数 如果是简单类型,默认会被认为是@RequestParam参数

返回值

返回值 描述
@ResponseBody 返回值通过HttpMessageWriter实例写入响应,其实就是返回
HttpEntity OR ResponseEntity 这个可以指定请求头和请求体,very 强大
HttpHeaders 返回只有请求头,没有请求体
String 返回可以由ViewResolver解析的视图名称
View 返回某个动态页面文件
java.util.Map,org.springframework.ui.Model 添加各种参数到隐式对象中,相当于request.setAttribute
@ModelAttribute 模型参数
void 根据请求的url返回视图
Rendering 不清楚
Flux<ServerSentEvent>, Observable<ServerSentEvent>, or other reactive type 暂时没见过 😰
其他返回类型 作为视图名处理

类型转换

对于一些基于注解的controller方法参数: @RequestParam,@PathVariable等,可能需要进行类型转换,他们默认的类型是String类型,对于简单的类型转换,如由String转换成int ,long等,Sping自动就转换了,对于其他的可以参考Spring FIeld Formatting

矩阵变量

Spring默认没有开启矩阵变量这种写法,需要进行配置

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. 最简单的矩阵变量

类似于普通的查询参数,矩阵变量也需要一个类似于占位符的东西,去表示 它

// GET /pets/42;q=11;r=22
​
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
​
 // petId == 42
 // q == 11
}
  1. 所有的路径段可能全都包含矩阵变量,有时候需要区分矩阵变量
// 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. 可以给矩阵变量设置为option和一个默认值
// 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

可以获取请求参数

@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 中请求参数的概念包含了查询参数,表单数据,和multipart的数据,在WebFlux中这些数据都可以通过ServletWebExchange获取,@ReuqestParam默认只绑定了查询参数

@RequestParam还可以用来加在Map<String, String> or MultiValueMap<String, String>上,这样可以得到所有的查询参数

@RequestParam注解使用后,后边参数的类型就不会被其他参数解析器去解析,说白了就是它后边智能加常见的基本类型,不能加自定义的Java Bean

@Requestheader

获取请求头信息

例如:

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>

可以指定得到哪些请求头

下面这个例子: 得到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参数上,这样可以得到

Spring内置支持将一个由,分割的字符串,转变成字符串数据或者集合,例如: @RequestHeader("Accept" 返回的结果可能是String但是也可能是String[],List<String>

@CookieValue

获取Cookie信息

@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { 
 //...
}

@ModelAttribute

可以将请求的参数,进行数据绑定成一个Java Bean

模型参数包含请求的查询参数和与字段名相同的表单字段信息,然后进行封装,这就是数据绑定WebExchangeDataBinder会进行查询参数,表单字段与声明的字段信息进行匹配,封装成想要的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";
 }
​
}

数据绑定可能出错,可以通过使用BindingResult来对可能出现的异常进行处理

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { 
 if (result.hasErrors()) {
 return "petForm";
 }
 // ...
}

还可以在数据绑定之后加入验证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中,支持响应式的模型,不能再@ModelAttribute之前申明任何一个响应式的模型,响应式可以这样子处理错误

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public Mono<String> processSubmit(@Valid @ModelAttribute("pet") Mono<Pet> petMono) {
 return petMono
 .flatMap(pet -> {
 // ...
 })
 .onErrorResume(ex -> {
 // ...
 });
}

@SessionAttributes

@SessionAttributes用来将请求之间的模型数据存储到WebSession中,它是一个类层级的注解

@Controller
@SessionAttributes("pet") 
public class EditPetForm {
 // ...
}

当一个请求,带有pet的模型参数时,它的数据就会被自动存储到WebSession中,直到一个Controlelr方法使用SessionStatus为参数进行清除存储

@Controller
@SessionAttributes("pet") 
public class EditPetForm {
​
 // ...
​
 @PostMapping("/pets/{id}")
 public String handle(Pet pet, BindingResult errors, SessionStatus status) { 
 if (errors.hasErrors) {
 // ...
 }
 status.setComplete();
 // ...
 }
 }
}

@SessionAttribute

可以访问全局的已经存在的session

@GetMapping("/")
public String handle(@SessionAttribute User user) { 
 // ...
}

如果想要添加或者删除全局的session,可以在controller中注入WbbSession

@RequestAttribute

@SessionAttribute类似,它可以获取已经存在的请求参数

Multipart Content

我没用过😅

@RequestBody

读请求体的内容,通过HttpMessageReader反序列化为对象

@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
 // ...
}

与Spring MVC不同的是,注解参数支持响应式类型

@PostMapping("/accounts")
public void handle(@RequestBody Mono<Account> account) {
 // ...
}

这个可以结合javax.validation.Valid,Spring的@Validated使用,默认情况下,验证错误将会引起WebExchangeBindException会出现400(BAD_REQUEST),我们可以使用Errorsor BindingResult参数来处理错误

@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
 // ...
}

HttpEntity

或多或少等同于@RequestBody,它包含了request暴露出来的请求头和请求体

@ResponseBody

将返回的信息序列化使用HttpMessageWriter到请求体中

@ResponseBody支持方法级别,也支持类级别

ResponseEntity

包含了请求的头,体,状态码,三种信息

Jackson JSON

Spring WebFlux提供了Jackson JSON(支持序列化)

管理异常

对于一个REST 服务来说,通常需要将错误信息展示在请求体中,Spring没有自动实现,因为响应正文中的错误是针对特定的应用的。我们可以在@RestController类中,写一个@ExceptionHanlder注解的方法,用ResponseENtity作为返回值,去设置返回的各种信息。也可以将这种方法写在@ControllerAdvice注解的类中,用于全局

Controller Advice

对于一些全局的操作可以放在这里,常用的就是异常处理了

默认,每次请求,都会经过这里,但是可以通过注解的一些参数来限制

// 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

浏览器的结果自然就是设定的ResponseEntity

相关文章

网友评论

      本文标题:WebFlux-Annotated Controllers

      本文链接:https://www.haomeiwen.com/subject/venedqtx.html