Spring Security入门(八) 使用Spring MVC开发RESTful API-错误处理

一.导学
  • Spring boot中默认的错误处理机制
  • 自定义异常处理
二.spring boot中默认的错误处理机制
  • 访问一个不存在的url
http://localhost:8070/xxx
  • 浏览器的默认错误如下图所示
    在这里插入图片描述
  • 浏览器的处理(我们先访问正常页面)
http://localhost:8070/user/1

在这里插入图片描述

  • 获取用户信息的请求,返回的是json格式的用户信息

  • 我们再访问不存在的url 看看浏览器是怎么处理的
    在这里插入图片描述
    总结:浏览器发的时候响应是一段html,客户端发的时候是一段json。Spring boot默认处理机制,它会判断当前请求是浏览器发的还是客户端发送的,根据不同请求有不同的处理

  • 我们来看看源码是怎么操作的

  • 在BasicErrorController 这个类(Spring boot内部错误处理的控制器)

在这里插入图片描述

  • 有两个RequstMapping
  • 区别在于请求头中有没有text/html参数
  • ResponseBody注解 把map转换成json
    在这里插入图片描述
  • 浏览器请求头第一个就是text/html
    在这里插入图片描述
  • 而客户端并不含有text/html
  • restfull api 是通过http状态码返回不同的场景,所以这里status是404.而且请求响应状态也是404,自己在设计的时候可以参考这个思想
  • 还有一个提示信息 “No message available” 404 状态就是没有找到可处理的路径,没有可用的信息也符合解释
  • 但是在实际开发中,只是凭借http状态码的话,是不能解决实际场景中的需求的
  • 比如创建用户信息,缺少字段,需要返回哪一个字段缺少
  • 在spring 默认的处理中,使用 @Valid 但是不声明BindingResult的时候,会把很详细的验证信息返回去
 @PostMapping
    public User create(@Valid  @RequestBody  User user /*,BindingResult errors*/){
       /* if(errors.hasErrors()){
                    errors.getAllErrors().stream().forEach(System.out::println);
        }*/
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getPassword());
        System.out.println(user.getBirthday());

        user.setId("1");
        return user;
    }
  • json拼装成user对象(发送一段不合法的json 或者直接为空)
  • 不满足这些注解条件 直接打回去 返回400 请求错误的状态码
  • 400不足以告诉它发生了什么 你需要告诉它那个字段校验不过
    在这里插入图片描述
  • Errors里面有明确的错误信息
  • 当发出请求不合法时,Spring boot会默认把这些错误请求收集起来拼成Errors返回给前台 根据这些信息可以看到那些信息有问题 问题是什么
  • 前两个例子都是没有进入到自己写的控制器类,被spring框架打回去了 不管400还是404,然后错误信息给前端,让前端来处理
  • 开发中最常见,进入到Controller方法中 甚至调用了一些服务层的服务 由这些服务抛出的异常,Spring boot这种情况默认是怎么处理的?
    @GetMapping(value = "/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String idxxx){
        throw new RuntimeException("user not exist");//简化 不写服务层了
    }
  • 浏览器响应
    在这里插入图片描述

  • 客户端响应
    在这里插入图片描述

  • spring boot 默认的处理机制已经介绍完了,大部分默认的机制就能满足需要

  • 下面介绍如果不满足需求,要怎么自定义处理行为

三.自定义错误处理
1.自定义浏览器错误处理
在资源文件夹下创建对应状态码的html页面就可以了
|- resources
  |- error
    |- 404.html
    |- 500.html

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>404</title>
</head>
<body>
       <h1>你访问的页面并不存在</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>500</title>
</head>
<body>
        <h1>服务器内部错误</h1>
</body>
</html>
  • 验证一下效果
  • 先访问一个不存在的url
http://localhost:8070/xxx

在这里插入图片描述

  • 再访问一下
http://localhost:8070/user/1

在这里插入图片描述

  • 看看是不是对客户端无效
    在这里插入图片描述
    在这里插入图片描述
  • 仍然是json返回,定义404只对浏览器发出请求有作用,两者互不影响
2.自定义客户端错误处理
  • 异常错误信息,有时候异常不止包含错误信息,可能包含一些其他信息
  • 先自定义一个异常类
public class UserNotExistException extends RuntimeException{

    private String id;

    public UserNotExistException(String id) {
        super("user not exist");
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  @GetMapping(value = "/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String idxxx){
        throw new UserNotExistException(idxxx);
    }
  • 默认spring boot不会读异常以外的其他信息的,如何把id返回包含到json信息中?
  • 异常处理器(这个类写的方法都是用来处理其他Controller所抛出的异常 本身不负责处理http请求 负责其他Controller抛出的异常)
@ControllerAdvice //任何控制器任何方法抛出这个异常 都会跳到这个方法中来处理
public class ControllerExceptionHandler {

    @ExceptionHandler(UserNotExistException.class) //处理什么异常
    @ResponseBody //把map转成json串给前端响应
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //状态码 500
    public Map<String,Object> handlerUserNotExistException(UserNotExistException ex){
         Map<String,Object> map = new HashMap<>();
            map.put("id",ex.getId());
            map.put("message",ex.getMessage());
          return map;
    }
}
  • 响应的json串完全根据自己写的map来定义的
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值