基于注解的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;
}
}
- 最简单的矩阵变量
类似于普通的查询参数,矩阵变量也需要一个类似于占位符的东西,去表示 它
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
- 所有的路径段可能全都包含矩阵变量,有时候需要区分矩阵变量
// 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
}
- 可以给矩阵变量设置为option和一个默认值
// 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
可以获取请求参数
@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
),我们可以使用Errors
or 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
网友评论