SpringBoot开发RESTful API

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 OK
  • 400 Bad Request
  • 500 Internal Server Error

通常200表示成功,400表示客户端错误(请求格式),500表示服务端错误(服务内部异常)

其他常用状态码:

  • 201 已创建。成功请求并创建了新的资源
  • 3xx 代表的是重定向,例如301(永久移动)、303重定向、302(暂时移动)
  • 401 未通过身份认证
  • 403 拒绝服务该请求
  • 409 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
  • 410 资源曾经存在,但目前被永久删除。
  • 502 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
  • 504 充当网关或代理的服务器,未及时从远端服务器获取请求

其他状态码可以参考:

HTTP状态码 | 菜鸟教程

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/