4.使用Spring MVC开发RESTful API(二)

startshineye

1.6 服务异常处理

Restful API错误处理分为以下:

  1. SpringBoot中默认处理机制
  2. 自定义异常处理

1.6.1 SpringBoot中默认处理机制

当我们随便访问一个不存在的url请求时候,会返回异常:http://127.0.0.1:8088/xxx
12.png

出现空白错误页:404
在前后端分离架构下,Restful API往往会有多个渠道访问:浏览器、app等,很多能多终端都会访问以上接口

以上我们是使用浏览器访问,下面我们使用谷歌插件模拟app访问。
Restlet Client
百度云盘下载:链接:https://pan.baidu.com/s/1lbZ-...
提取码:u149

打开Chrome点击右上角三个点按钮->更多工具--扩展程序--选中开发者模式->将下载后的.crx文件拖入,如提示文件无效则将文件后缀名修改为.rar之后解压缩->点击“加载已解压的扩展程序”找到解压的文件夹路径确定

App端请求:
1.设置变量
13.png

2.引用变量请求
14.png

3.请求不存在的连接:http://127.0.0.1:8088/xxx
15.png

SpringBoot默认处理机制在App端返回了json;浏览器发送返回的是html

SpringBoot默认异常处理类源码:

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"}) //补货"/error"的请求
public class BasicErrorController extends AbstractErrorController {
    private final ErrorProperties errorProperties;

    public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        this(errorAttributes, errorProperties, Collections.emptyList());
    }

    public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorViewResolvers);
        Assert.notNull(errorProperties, "ErrorProperties must not be null");
        this.errorProperties = errorProperties;
    }

    public String getErrorPath() {
        return this.errorProperties.getPath();
    }

    //处理请求头Accept中包含:text/html的请求
    @RequestMapping(
        produces = {"text/html"}
    )
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
    }

   //接口请求中返回了json
    @RequestMapping
    @ResponseBody
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = this.getStatus(request);
        return new ResponseEntity(body, status);
    }

    protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
        IncludeStacktrace include = this.getErrorProperties().getIncludeStacktrace();
        if (include == IncludeStacktrace.ALWAYS) {
            return true;
        } else {
            return include == IncludeStacktrace.ON_TRACE_PARAM ? this.getTraceParameter(request) : false;
        }
    }

    protected ErrorProperties getErrorProperties() {
        return this.errorProperties;
    }
}

同一个异常,在不同终端返回的异常的设计方法:通过 produces = {"text/html"}验证。

我们使用Restlet Client 测试下存在的创建用户接口不合法校验时候(接口去掉:BindingResult处理类),SpringBoot默认异常处理:

分析:

  1. 之前我们抛出的异常,压根没有进入我们的业务方法里面就被SpringBoot框架给挡回去了,虽然会返回一些常见的错误码和错误信息供前端提示,但是很多时候使我们自己定义错误信息
  2. 大部分情况下SpringBoot默认自带的异常处理机制会自动帮我们返回错误信息了,但是在有些情况下不满足我们要求时候,我们需要自定义异常处理。
  3. SpringBoot自带的浏览器错误处理机制是根据状态码:status=404 来区分错误请求并返回html页面的;所以我们对此类异常处理可以根据状态码定义不同的html页面返回:

在:项目工程resources下创建:resources/error文件夹,里面存放404.html。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>404</title>
</head>
<body>
    您访问的页面不存在
</body>
</html>

此时我们再次访问:http://127.0.0.1:8088/xxx时候
18.png

我们查看SpringBoot异常处理类源码:

19.png

我们在App端访问如下:
20.png

1.6.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;
    }
}

然后我们在接口:DetailInfo中抛出异常

@GetMapping("/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User DetailInfo(@PathVariable(name = "id") String xxx){
    throw new UserNotExistException(xxx);
}

web端请求:
21.png

输出自定义的500异常处理页面

app端请求:
22.png

上面异常已经使我们定义的异常了,但是异常的属性id没有传出去:

我们定义全局异常处理类:

GeneralException:

此类里面的所有方法,都是处理其他类所抛出的异常,他本身不处理Http请求,他只处理其他类所抛出的异常。 具体处理什么异常?在注解:

@ControllerAdvice
public class GeneralExceptionHandler {

    @ExceptionHandler(UserNotExistException.class)
    @ResponseBody//map转化成json
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//错误码返回500
    public Map<String,Object> handleUserNotExistException(UserNotExistException ex){
        Map<String, Object> result = new HashMap<>();
        result.put("id",ex.getId());
        result.put("message",ex.getMessage());
        return result;
    }
}

此时浏览器端访问:
23.png

此时App接口访问:
24.png

阅读 1.2k

我在规定的时间内,做到了我计划的事情;我自己也变得自信了,对于外界的人跟困难也更加从容了,我已经很强...

54 声望
13 粉丝
0 条评论
你知道吗?

我在规定的时间内,做到了我计划的事情;我自己也变得自信了,对于外界的人跟困难也更加从容了,我已经很强...

54 声望
13 粉丝
文章目录
宣传栏