likes
comments
collection
share

【基础篇】SpringBoot 统一接口响应与异常响应处理

作者站长头像
站长
· 阅读数 9

写在最前

统一接口响应与异常响应是基本的开发规范,如今我们的项目已大多是前后端分离的方式,统一处理响应,能够减少前后端团队联调接口的不必要的沟通。

Deom 地址:mingyue-springboot-global-resp-exception

统一接口响应

本 Demo 改造 mingyue-springboo-api,原接口代码如下:

@GetMapping("/{userId}")
public ResponseEntity<MingYueUser> queryUserById(@PathVariable Long userId) {
    return ResponseEntity.ok(mingYueUserService.queryUserById(userId));
}

原接口响应如下:

{
	"userId": 1,
	"username": "mingyue"
}

1. 添加统一响应类

package com.csp.mingyue.global.util;

import com.csp.mingyue.global.constant.CommonConstants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * 响应信息主体
 *
 * @param <T>
 * @author Strive
 */
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class R<T> implements Serializable {

	private static final long serialVersionUID = 1L;

	@Getter
	@Setter
	private int code;

	@Getter
	@Setter
	private String msg;

	@Getter
	@Setter
	private T data;

	public static <T> R<T> ok() {
		return restResult(null, CommonConstants.SUCCESS, null);
	}

	public static <T> R<T> ok(T data) {
		return restResult(data, CommonConstants.SUCCESS, null);
	}

	public static <T> R<T> ok(T data, String msg) {
		return restResult(data, CommonConstants.SUCCESS, msg);
	}

	public static <T> R<T> failed() {
		return restResult(null, CommonConstants.FAIL, null);
	}

	public static <T> R<T> failed(String msg) {
		return restResult(null, CommonConstants.FAIL, msg);
	}

	public static <T> R<T> failed(T data) {
		return restResult(data, CommonConstants.FAIL, null);
	}

	public static <T> R<T> failed(T data, String msg) {
		return restResult(data, CommonConstants.FAIL, msg);
	}

	public static <T> R<T> restResult(T data, int code, String msg) {
		R<T> apiResult = new R<>();
		apiResult.setCode(code);
		apiResult.setData(data);
		apiResult.setMsg(msg);
		return apiResult;
	}

}

2. 编写响应接口

@GetMapping("/{userId}")
public R<MingYueUser> queryUserById(@PathVariable Long userId) {
  return R.ok(mingYueUserService.queryUserById(userId));
}

3. 测试接口响应

curl --location --request GET 'http://127.0.0.1:8080/user/1' \
--header 'User-Agent: Apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
--header 'Connection: keep-alive'

接口响应如下:

{
    "code": 0,
    "msg": null,
    "data": {
        "userId": 1,
        "username": "mingyue"
    }
}

统一异常处理

1. 添加自定义业务异常

package com.csp.mingyue.global.exception;

import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Strive
 * @date 2018/6/22 16:21:57
 */
@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	/**
	 * 状态码
	 */
	private int code;

	public BusinessException(String message) {
		super(message);
	}

	public BusinessException(int code, String message){
		super(message);
		this.code = code;
	}

}

2. 添加全局异常处理

package com.csp.mingyue.global.handler;

import com.csp.mingyue.global.exception.BusinessException;
import com.csp.mingyue.global.util.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author Strive
 * @date 2023/5/8 17:16
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 捕获 Controller 中抛出的指定类型的异常,也可以指定其他异常
     * @param exception
     * @return
     * @param <E>
     */
    @ExceptionHandler(value = Exception.class)
    public <E>R<E> handler(Exception exception){
        if (exception instanceof BusinessException){
            BusinessException businessException = (BusinessException) exception;
            return R.failed(businessException.getCode(),businessException.getMessage());
        } else {
            return R.failed(500, "系统异常:" + exception.getMessage());
        }
    }

}

3. 编写异常接口

@GetMapping("/exception/{userId}")
public R<MingYueUser> queryUserByIdError(@PathVariable Long userId) {

  if (1 == 1) {
    throw new BusinessException(316, "测试业务异常返回");
  }

  return R.ok(mingYueUserService.queryUserById(userId));
}

4. 测试异常接口返回

curl --location --request GET 'http://127.0.0.1:8080/user/exception/1' \
--header 'User-Agent: Apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8080' \
--header 'Connection: keep-alive'

接口响应如下:

{
    "code": 316,
    "msg": "测试业务异常返回",
    "data": null
}

小结

  • @ControllerAdvice、@RestControllerAdvice 即可开启全局异常处理,使用该注解表示开启了全局异常的捕获。
  • @ExceptionHandler 注解定义捕获异常的类型即可对这些捕获的异常进行统一的处理。