RESTful API
RESTful API是面向资源的,他认为一切URI皆资源,所以URI一定要是名词而不是动词,动词的含义通过请求方法来表达。有了资源还需要确定如何表现这个资源,例如JSON、XML,这就称为表现层。
GET /getUserInfo?id=15
->GET /users/15
也不要在URI中加入版本号,例如/v1/users
,如果需要多版本的API,请在请求中带上版本号,例如Accept: version = 1.0
。
概括:
- 看URL就知道要什么资源
- 看http method就知道针对资源干什么
- 看http status code就知道结果如何
常用请求方法:
- GET : 获取、读取资源
- POST : 添加资源
- PUT : 修改资源
- DELETE : 删除资源
基础状态码:
200
OK400
Bad Request500
Internal Server Error
通常200表示成功,400表示客户端错误(请求格式),500表示服务端错误(服务内部异常)
其他常用状态码:
201
已创建。成功请求并创建了新的资源3xx
代表的是重定向,例如301(永久移动)、303重定向、302(暂时移动)401
未通过身份认证403
拒绝服务该请求409
服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突410
资源曾经存在,但目前被永久删除。502
作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应504
充当网关或代理的服务器,未及时从远端服务器获取请求
其他状态码可以参考:
RESTful API相关注解
@RestController
:代替@Controller
+@ResponseBody
@xxxMapping
@GetMapping
:代替@RequestMapping(...,method=GET)
@PostMapping
:代替@RequestMapping(...,method=POST)
@PutMapping
:代替@RequestMapping(...,method=PUT)
@DeleteMapping
:代替@RequestMapping(...,method=DELETE)
@PathVariable
:接收URL上的参数@RequestParam
:接收请求体上的参数
在@xxxMapping
和@RequestMapping
中,有两个属性需要关注:consumes和produces,可以为它们指定MediaType
中的值来限定该方法接收什么类型的请求体和返回什么类型。
@PathVariable
示例:
//请求的url例如“/article/1”
@DeleteMapping("/article/{id}")
public @ResponseBody AjaxResponse deleteArticle(@PathVariable Long id) {
@RequestBody
:接收请求体中的复杂数据并转为java对象
JSON数据和Java对象自动通过HttpMessageConverter(这是一个接口,具体到JSON有Jackson提供的实现类)完成转换。
处理HTTP状态码、异常和响应头
如果只用@RestController
搭配方法返回String,那么显然只能关注响应体,如果需要处理HTTP状态码、方法中可能出现的异常和响应头,就需要额外的操作。
Spring提供了实体封装类ResponseEntity
和注解@ResponseStatus
。
ResponseEntity
可以有效地封装错误消息、响应头和状态码,@ResponseStatus
相对功能更少,可以配置指定的状态码返回给客户端。(HttpStatus
中枚举了许多状态码)
示例:(使用了lombok)
@Slf4j
@RestController
@RequestMapping("/article")
public class ArticleRestController {
//增加一篇Article ,使用POST方法
@ResponseStatus(HttpStatus.CREATED)
@RequestMapping(value = "/", method = POST, produces = "application/json")
public String saveArticle(@RequestBody Article article) {
log.info("saveArticle:{}",article);
return "{\"status\":1,\"msg\":\"success\"}";
}
//获取一篇Article ,使用GET方法
@RequestMapping(value = "/{id}", method = GET, produces = "application/json")
public ResponseEntity<Article> getArticle(@PathVariable long id) {
Article article = Article.builder()
.id(1)
.author("123")
.content("456")
.createTime(new Date())
.title("789").build();
HttpHeaders headers = new HttpHeaders();
headers.add("success","success");
return new ResponseEntity<>(article,headers,HttpStatus.OK);
}
}
至于处理异常,需要两个注解:@ControllerAdvice
和@ExceptionHandler
。
@ControllerAdvice
的作用是给控制器增加通知,作用于类上,定义了一个控制器的通知类。
@ExceptionHandler
配合@ControllerAdvice
使用定义控制器发生异常后的操作,一般来说,发生异常后,可以跳转到指定的错误页面,以避免用户使用的不友好。
示例(在MVC中):
@ControllerAdvice(
//指定拦截的包
basePackages = {"com.rhett.bootweb.controller.*"},
//被标注为@Controller的类才拦截
annotations = Controller.class
)
public class ErrorControllerAdvice {
@ExceptionHandler
public String exception(Model model, Exception ex){
//给数据模型增加异常信息
model.addAttribute("exception_message",ex.getMessage());
//返回异常视图
return "exception";
}
}
示例(在RESTful API中):
@ControllerAdvice(
basePackages = {"com.rhett.bootweb.controller.*"},
annotations = Controller.class
)
public class ErrorControllerAdvice {
@ExceptionHandler
@ResponseBody
//返回错误状态码
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String,Object> exception(HttpServletRequest request, Exception ex){
Map<String,Object> msgMap = new HashMap<>();
//获取异常信息
msgMap.put("message",ex.getMessage());
msgMap.put("cause",ex.getStackTrace());
return msgMap;
}
}
@ExceptionHandler
还可以指定一个value,为某一个具体Excepetion的class对象,只针对某一具体异常进行拦截。
@ControllerAdvice
还可以配合@InitBinder
使用(在控制器参数转换前被执行的代码)
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/springboot%e5%bc%80%e5%8f%91restful-api/