>  기사  >  Java  >  SpringBoot 통합 인터페이스 반환 및 전역 예외를 처리하는 방법

SpringBoot 통합 인터페이스 반환 및 전역 예외를 처리하는 방법

PHPz
PHPz앞으로
2023-05-12 16:01:061792검색

1. SpringBoot는 통일된 반환 형식을 사용하지 않습니다.

기본적으로 SpringBoot에는 다음 세 가지 반환 상황이 있습니다.

1.1 문자열을 사용하여 반환

@GetMapping("/getUserName")
public String getUserName(){
    return "HuaGe";
}

인터페이스 호출을 통해 결과 반환:

HuaGe

1.2 엔터티 클래스를 사용하여 반환

@GetMapping("/getUserName")
public User getUserName(){
    return new User("HuaGe",18,"男");
}

인터페이스 호출로 결과 반환:

{
  "name": "HuaGe",
  "age": "18",
  "性别": "男", 
}

1.3 비정상적인 상황에서 반환

@GetMapping("/getUserName")
public static String getUserName(){
    HashMap hashMap = Maps.newHashMap();
    return hashMap.get(0).toString();
}

그렇지 않은 경우 널 포인터 예외 시뮬레이션 예외 처리를 수행할 때 SpringBoot의 기본 반환 결과를 살펴볼 수 있습니다:

{
    "timestamp": "2021-08-09T06:56:41.524+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "path": "/sysUser/getUserName"
}

위 상황의 경우 전체 프로젝트가 통합 반환 형식을 정의하지 않으면 5개 백엔드 개발자는 다섯 가지 반환 형식을 정의합니다. 코드가 비대해지고 프런트엔드 및 백엔드 도킹 효율성이 낮을 뿐만 아니라 프런트엔드에서 예외 세부 정보를 직접 표시하는 등 예상치 못한 상황이 발생할 수도 있습니다. 사용자 경험이 매우 좋지 않습니다.

2. 기본 게임 플레이

프로젝트에서 가장 일반적인 것은 반환해야 할 필드 정보를 클래스에 정의하고, 프런트 엔드에 반환해야 하는 인터페이스 정보를 캡슐화하는 것입니다. 이 클래스를 통해 반환 형식의 불일치를 해결할 수 있습니다.

2.1 매개변수 설명

  • code: 상태 코드, 통합된 상태 코드 세트는 백그라운드에서 유지 관리될 수 있습니다.

  • message: 설명 정보, 인터페이스 호출의 성공/실패에 대한 프롬프트 정보; ;

  • data: 데이터를 반환합니다.

2.2 프로세스 설명

  • 새 결과 클래스 만들기

public class Result<T> {
    
    private int code;
    
    private String message;
    
    private T data;

    public Result() {}
    public Result(int code, String message) {
        this.code = code;
        this.message = message;
    }
    
    /**
     * 成功
     */
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<T>();
        result.setCode(ResultMsgEnum.SUCCESS.getCode());
        result.setMessage(ResultMsgEnum.SUCCESS.getMessage());
        result.setData(data);
        return result;
    }

    /**
     * 失败
     */
    public static <T> Result<T> error(int code, String message) {
        return new Result(code, message);
    }
}

반환 상태 코드 정의

public enum ResultMsgEnum {
    SUCCESS(0, "成功"),
    FAIL(-1, "失败"),
    AUTH_ERROR(502, "授权失败!"),
    SERVER_BUSY(503, "服务器正忙,请稍后再试!"),
    DATABASE_OPERATION_FAILED(504, "数据库操作失败");
    private int code;
    private String message;

    ResultMsgEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public int getCode() {
        return this.code;
    }
    
    public String getMessage() {
        return this.message;
    }
}
  • Usage

위의 두 단계는 를 정의합니다. 데이터 반환 형식 및 상태 코드, 다음으로 인터페이스에서 이를 사용하는 방법을 살펴봐야 합니다. 数据返回格式状态码,接下来就要看下在接口中如何使用了。

@GetMapping("/getUserName")
public Result getUserName(){
    return Result.success("huage");
}

调用结果如下,可以看到是我们在Result中定义的参数类型。

{
    "code": 0,
    "message": "成功",
    "data": "huage"
}

这样写虽然能够满足日常需求,而且我相信很多小伙伴也是这么用的,但是如果我们有大量的接口,然后在每一个接口中都使用Result.success来包装返回信息,会新增很多重复代码,显得不够优雅,甚至都不好意思拿出去显摆。 肯定会有一种方式能够再一次提高代码逼格,实现最优解。

三、进阶用法

基本用法学会后,接下来看点究极版本,主要用到如下两个知识点,用法简单,无论是拿出来教学妹,还是指点小姐姐,都是必备技能。

3.1 类介绍

  • ResponseBodyAdvice: 该接口是SpringMVC 4.1提供的,它允许在 执行 @ResponseBody后自定义返回数据,用来封装统一数据格式返回;

  • @RestControllerAdvice: 该注解是对Controller进行增强的,可以全局捕获抛出的异常。

3.2 用法说明

  • 新建ResponseAdvice类;

  • 实现ResponseBodyAdvice接口,实现supportsbeforeBodyWrite方法;

  • 该类用于统一封装controller中接口的返回结果。

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 是否开启功能 true:是 
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    /**
     * 处理返回结果
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //处理字符串类型数据
        if(o instanceof String){
            try {
                return objectMapper.writeValueAsString(Result.success(o));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return Result.success(o);
    }
}

我们可以通过getUserName接口测试一下,会发现和直接使用Result返回的结果是一致的。

不过,细心的小伙伴们肯定注意到了,在ResponseAdvice我们全部使用了Result.success(o)来处理结果,对于error类型的结果未做处理。我们来看下,发生异常情况时,返回结果是什么样呢?继续使用上面HashMap空指针异常的代码,测试结果如下:

{
    "code": 0,
    "message": "成功",
    "data": {
        "timestamp": "2021-08-09T09:33:26.805+00:00",
        "status": 405,
        "error": "Method Not Allowed",
        "path": "/sysUser/getUserName"
    }
}

虽然格式上没有毛病,但是在code、data字段的具体数据上是不友好或不正确的。不处理好这些事情,会严重影响自己在前端妹妹心中的高大形象的,这是决不能容忍的。

3.3 全局异常处理器

以前我们遇到异常时,第一时间想到的应该是try..catch..finnal吧,不过这种方式会导致大量代码重复,维护困难,逻辑臃肿等问题,这不是我们想要的结果。

今天我们要用的全局异常处理方式,用起来是比较简单的。首先新增一个类,增加@RestControllerAdvice注解,该注解的作用花哥上面已经介绍过,就不再唠叨了。

@RestControllerAdvice
public class CustomerExceptionHandler {
    
}

如果我们有想要拦截的异常类型,就新增一个方法,使用@ExceptionHandler注解修饰,注解参数为目标异常类型。

例如:controller中接口发生Exception异常时,就会进入到Execption方法中进行捕获,将杂乱的异常信息,转换成指定格式后交给ResponseAdvice

@RestControllerAdvice
@Slf4j
public class CustomerExceptionHandler {

    @ExceptionHandler(AuthException.class)
    public String ErrorHandler(AuthorizationException e) {
        log.error("没有通过权限验证!", e);
        return "没有通过权限验证!";
    }

    @ExceptionHandler(Exception.class)
    public Result Execption(Exception e) {
        log.error("未知异常!", e);
        return Result.error(ResultMsgEnum.SERVER_BUSY.getCode(),ResultMsgEnum.SERVER_BUSY.getMessage());
    }
}

호출 결과는 Result에서 정의한 매개변수 유형임을 알 수 있습니다. 🎜
{
    "code": 0,
    "message": "成功",
    "data": {
        "code": 503,
        "message": "服务器正忙,请稍后再试!",
        "data": null
    }
}
🎜이 방법으로 작성하면 일상적인 요구 사항을 충족할 수 있고 많은 친구들이 이 방법을 사용한다고 생각하지만 인터페이스 수가 많은 경우 Result.success를 사용하여 각 인터페이스를 패키징하세요. 정보 반환 반복되는 코드를 많이 추가하게 되는데, 이는 우아하지도 않고 심지어 자랑하기조차 부끄럽습니다. 코드를 다시 개선하고 최적의 솔루션을 얻을 수 있는 방법이 있어야 합니다. 🎜🎜3. 고급 사용법🎜🎜 기본 사용법을 익힌 후 최종 버전을 살펴보겠습니다. 주로 다음 두 가지 지식 포인트를 사용합니다. 또는 소녀들에게 조언을 해주세요. 🎜🎜3.1 클래스 소개🎜🎜🎜🎜🎜ResponseBodyAdvice: 🎜 이 인터페이스는 SpringMVC 4.1에서 제공되며 @ResponseBody 실행 후 사용자 정의 반환 데이터를 허용하며 통합 데이터 형식 반환을 캡슐화하는 데 사용됩니다. 🎜🎜🎜@RestControllerAdvice: 🎜 이 주석은 컨트롤러를 향상시키고 전역적으로 발생한 예외를 캡처할 수 있습니다. 🎜🎜🎜🎜3.2 사용 지침🎜🎜🎜🎜새 ResponseAdvice 클래스를 생성하고 🎜🎜🎜🎜ResponseBodyAdvice 인터페이스를 구현하고 지원을 구현합니다. beforeBodyWrite 메서드; 🎜🎜🎜🎜이 클래스는 인터페이스의 반환 결과를 컨트롤러에 균일하게 캡슐화하는 데 사용됩니다. 🎜🎜🎜
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 是否开启功能 true:开启
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    /**
     * 处理返回结果
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //处理字符串类型数据
        if(o instanceof String){
            try {
                return objectMapper.writeValueAsString(Result.success(o));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        //返回类型是否已经封装
        if(o instanceof Result){
            return o;
        }
        return Result.success(o);
    }
}
🎜 getUserName 인터페이스를 통해 테스트할 수 있으며, Result를 직접 사용하여 반환된 결과가 일치하는 것을 확인할 수 있습니다. 🎜🎜그러나 신중한 친구들은 ResponseAdvice에서 우리 모두가 결과를 처리하기 위해 Result.success(o)를 사용하고 오류 유형의 결과는 처리되지 않는다는 것을 알아차렸을 것입니다. 예외가 발생했을 때 반환 결과는 무엇인지 살펴보겠습니다. 위의 HashMap 널 포인터 예외 코드를 계속 사용해본 결과 테스트 결과는 다음과 같습니다. 🎜rrreee🎜 형식에는 문제가 없지만 코드 및 데이터 필드의 특정 데이터가 친숙하지 않거나 올바르지 않습니다. 이러한 문제를 해결하지 못하면 프런트 엔드 자매의 마음 속에 있는 당신의 키 큰 이미지에 심각한 영향을 미칠 것이며 이는 결코 용납되지 않을 것입니다. 🎜🎜3.3 전역 예외 처리기🎜🎜과거에 예외가 발생했을 때 가장 먼저 떠오른 것은 try..catch..finnal이었습니다. 그러나 이 방법은 많은 코드 중복, 유지 관리 어려움, 비대화로 이어질 것입니다. 논리와 다른 문제는 우리가 원하는 결과가 아닙니다. 🎜🎜오늘 사용할 전역 예외 처리 방법은 비교적 사용이 간단합니다. 먼저 새 클래스를 추가하고 @RestControllerAdvice 주석을 추가합니다. 이 주석의 기능은 위에서 소개되었으므로 자세히 설명하지 않겠습니다. 🎜rrreee🎜가로채고 싶은 예외 유형이 있는 경우 새 메서드를 추가하고 @ExceptionHandler 주석을 사용하여 수정하면 주석 매개변수가 대상 예외 유형이 됩니다. 🎜🎜예: 컨트롤러의 인터페이스에서 예외가 발생하면 Execution 메서드를 입력하여 이를 캡처하고 지저분한 예외 정보를 지정된 형식으로 변환하여 에 전달합니다. ResponseAdvice 메서드는 통합 형식으로 캡슐화되어 프런트 엔드 파트너에게 반환됩니다. 🎜
@RestControllerAdvice
@Slf4j
public class CustomerExceptionHandler {

    @ExceptionHandler(AuthException.class)
    public String ErrorHandler(AuthorizationException e) {
        log.error("没有通过权限验证!", e);
        return "没有通过权限验证!";
    }

    @ExceptionHandler(Exception.class)
    public Result Execption(Exception e) {
        log.error("未知异常!", e);
        return Result.error(ResultMsgEnum.SERVER_BUSY.getCode(),ResultMsgEnum.SERVER_BUSY.getMessage());
    }
}

再次调用接口getUserName查看返回结果,会发现还是有一些问题,因为我们在CustomerExceptionHandler中已经将接口返回结果封装成Result类型,而代码执行到统一结果返回类ResponseAdvice时,又会结果再次封装,就出现了如下问题。

{
    "code": 0,
    "message": "成功",
    "data": {
        "code": 503,
        "message": "服务器正忙,请稍后再试!",
        "data": null
    }
}

3.4 统一返回结果处理类最终版

解决上述问题非常简单,只要在beforeBodyWrite中增加一条判断即可。

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 是否开启功能 true:开启
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    /**
     * 处理返回结果
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //处理字符串类型数据
        if(o instanceof String){
            try {
                return objectMapper.writeValueAsString(Result.success(o));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        //返回类型是否已经封装
        if(o instanceof Result){
            return o;
        }
        return Result.success(o);
    }
}

위 내용은 SpringBoot 통합 인터페이스 반환 및 전역 예외를 처리하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제