您的位置:首页 > 编程语言 > Java开发

Spring Security技术栈开发企业级认证与授权(四)RESTful API服务异常处理

2018-04-01 15:14 513 查看
当我们从浏览器访问不存在的
Spring Boot
RESTful API
的时候,往往会返回
Spring Boot
内置的
404
错误界面,但是作为前后端分离的应用,相同的
API
也许会在其他终端访问,比如手机
APP
等,那么也会是相同的处理方式吗?

一、Spring Boot的默认处理方式分析

从浏览器端访问

启动
Spring Boot
项目,从浏览器访问一个不存在的
API
,如“
/user/hello
”,这时候返回来的是一个
HTML
页面,如下图所示:



APP
端访问

APP
端访问我们可以使用模拟
RESTful API
发送器来进行发送,我这里使用的
Paw
软件,你可以在你的谷歌浏览器上安装
Postman
来进行发送。访问“
/user/hello
”返回的结果如下如所示:



对比上面的两种访问方式,返回的错误类型是不一样的,浏览器访问返回的是一个
HTML
页面,而客户端访问返回的是一个
JSON
数据。那么问题来了,
Spring Boot
是如何确定当前请求来自浏览器还是客户端?我们可以从它的源代码中找到答案。

这段源代码来自于
Spring Boot
的一个包
org.springframework.boot.autoconfigure.web
中的
BasicErrorController
,从类名就可以知道它是一个
Controller
,且处理的路径就是“
/error
”。找到错误处理的两个方法,如下图所示:



第一个方法和第二个方法处理的都是同一个
API
,区别就在于第一个方法的
@RequestMapping
里面包含一个
produces
属性,它表示将生成什么类型的资源返回给前端,很明显,第一个方法要返回的是一个
HTML
页面,而第二个方法返回的是
JSON
数据。这就很明了了,当浏览器访问错误的
API
的时候,会自动进入第一个方法处理错误,从客户端访问的时候,就会进入第二个方法处理错误。当然,从浏览器发送的请求的时候,我们可以看见请求头中看到浏览器要求的返回数据类型就包含了
text/html
,如下图所示:



以上的例子都是访问资源不存在的案例,访问的处理逻辑并未进入对应的
Controller
就被
Spring Boot
打回去了,如果是服务代码抛出了异常,
Spring Boot
是如何处理的呢?在这里我再写一个
Controller
,手动抛出异常。代码如下:

@GetMapping("/user5")
@ResponseBody
public User user5() {
throw new RuntimeException("User is not exist.");
}


从浏览器端访问
http://localhost:8080/user5
,返回的依然是
HTML
页面,如下所示:



而从客户端访问,返回的依然是
JSON
数据,如下图所示:



二、自定义服务异常处理

在实际的开发过程中,如果出现
404
或者
500
的错误的时候,返回给浏览器是
Spring Boot
默认的处理界面,这并不友好,我们可以实现自定义页面来给出更好的温馨提示。

浏览器端自定义处理方式

这里仅仅介绍一种最简单的方式来处理异常,在
resources
文件夹下再建立一个
resources
文件夹,然后再在新建的
resources
文件夹下建立一个
error
,在
error
文件夹里面建立
404.html
500.html
,在访问出现
404
错误的时候,就会跳转到我们自己定义的
HTML
中,而不是
Spring Boot
默认的界面。

自定义服务异常处理类

在实际的开发中,我们完全可以自定义服务异常处理类,以满足实际的开发需求。这里写一个异常类,在业务逻辑处理中,可以根据需要手动抛出自己自定义的异常。比如:

package com.lemon.security.web.exception;

import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* @author lemon
* @date 2018/4/1 下午2:08
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class UserNotExistException extends RuntimeException {

private Integer id;

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


为了测试,在
Controller
添加一个方法,代码如下:

@GetMapping("/user6/{id:\\d+}")
@ResponseBody
public User user6(@PathVariable Integer id) {
throw new UserNotExistException(id);
}


当访问这个
API
的时候,就会抛出我们自定义的异常,这时候,
Spring Boot
默认的处理方式返回的结果如下图:



有时候我们前端不需要这么多的信息,只需要部分信息,这个时候就需要自定义异常处理了,而不是采用
Spring Boot
的默认处理方式了,在这里,我们可以写一个异常处理类,专门用来处理自定义异常。

package com.lemon.security.web.exception.handler;

import com.lemon.security.web.exception.UserNotExistException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.HashMap;
import java.util.Map;

/**
* 自定义错误处理逻辑
*
* @author lemon
* @date 2018/4/1 下午2:48
*/
@ControllerAdvice
public class UserNotExistExceptionHandler {

@ExceptionHandler(UserNotExistException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
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;
}
}


当一个类加上了
@ControllerAdvice
注解,那么这个类就具备了处理其他
Controller
异常的能力,具体的处理方式还是通过方法来进行的。上面的方法就是专门来处理
UserNotExistException
这个异常的,
@ExceptionHandler
就是指定了需要被处理的异常,
@ResponseStatus
指定状态码,最后将处理后的数据返回。定义好这个类之后,当代码中抛出了
UserNotExistException
异常的时候,都会转到这个方法中进行处理。再次运行应用,访问
http://localhost:8080/user6/1
返回的数据如下如所示:



这就是我们自定义的异常处理后的数据了。

Spring Security技术栈开发企业级认证与授权系列文章列表:

Spring Security技术栈开发企业级认证与授权(一)环境搭建

Spring Security技术栈开发企业级认证与授权(二)使用Spring MVC开发RESTful API

Spring Security技术栈开发企业级认证与授权(三)表单校验以及自定义校验注解开发

Spring Security技术栈开发企业级认证与授权(四)RESTful API服务异常处理

Spring Security技术栈开发企业级认证与授权系列文章列表:

Spring Security技术栈开发企业级认证与授权(一)环境搭建

Spring Security技术栈开发企业级认证与授权(二)使用Spring MVC开发RESTful API

Spring Security技术栈开发企业级认证与授权(三)表单校验以及自定义校验注解开发

Spring Security技术栈开发企业级认证与授权(四)RESTful API服务异常处理

Spring Security技术栈开发企业级认证与授权(五)使用Filter、Interceptor和AOP拦截REST服务

Spring Security技术栈开发企业级认证与授权(六)使用REST方式处理文件服务

Spring Security技术栈开发企业级认证与授权(七)使用Swagger自动生成API文档

示例代码下载地址:

项目已经上传到码云,欢迎下载,内容所在文件夹为
chapter004
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: