기본적으로 SpringBoot에는 다음 세 가지 반환 상황이 있습니다.
@GetMapping("/getUserName") public String getUserName(){ return "HuaGe"; }
인터페이스 호출을 통해 결과 반환:
HuaGe
@GetMapping("/getUserName") public User getUserName(){ return new User("HuaGe",18,"男"); }
인터페이스 호출로 결과 반환:
{ "name": "HuaGe", "age": "18", "性别": "男", }
@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개 백엔드 개발자는 다섯 가지 반환 형식을 정의합니다. 코드가 비대해지고 프런트엔드 및 백엔드 도킹 효율성이 낮을 뿐만 아니라 프런트엔드에서 예외 세부 정보를 직접 표시하는 등 예상치 못한 상황이 발생할 수도 있습니다. 사용자 경험이 매우 좋지 않습니다.
프로젝트에서 가장 일반적인 것은 반환해야 할 필드 정보를 클래스에 정의하고, 프런트 엔드에 반환해야 하는 인터페이스 정보를 캡슐화하는 것입니다. 이 클래스를 통해 반환 형식의 불일치를 해결할 수 있습니다.
code: 상태 코드, 통합된 상태 코드 세트는 백그라운드에서 유지 관리될 수 있습니다.
message: 설명 정보, 인터페이스 호출의 성공/실패에 대한 프롬프트 정보; ;
data: 데이터를 반환합니다.
새 결과 클래스 만들기
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
来包装返回信息,会新增很多重复代码,显得不够优雅,甚至都不好意思拿出去显摆。 肯定会有一种方式能够再一次提高代码逼格,实现最优解。
基本用法学会后,接下来看点究极版本,主要用到如下两个知识点,用法简单,无论是拿出来教学妹,还是指点小姐姐,都是必备技能。
ResponseBodyAdvice: 该接口是SpringMVC 4.1提供的,它允许在 执行 @ResponseBody
后自定义返回数据,用来封装统一数据格式返回;
@RestControllerAdvice: 该注解是对Controller进行增强的,可以全局捕获抛出的异常。
新建ResponseAdvice
类;
实现ResponseBodyAdvice
接口,实现supports
、beforeBodyWrite
方法;
该类用于统一封装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字段的具体数据上是不友好或不正确的。不处理好这些事情,会严重影响自己在前端妹妹心中的高大形象的,这是决不能容忍的。
以前我们遇到异常时,第一时间想到的应该是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 } }
解决上述问题非常简单,只要在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 중국어 웹사이트의 기타 관련 기사를 참조하세요!