本篇内容相对比较简单,不涉及具体的物联网技术,是作为后端工程师的基本操作,算是对基础框架的封装工作,我们使用 SpringBoot 的 RestControllerAdvice 与 ExceptionHandler 等注解实现对客户端请求响应的统一封装以及异常信息拦截封装。
为了保证我们前端在对接服务接口时采用统一的规范,业界主流的做法便是将所有请求的结果进行封装,当然在遇到异常信息时也进行一层封装,这样可以使所有接口的响应结构是一致的,响应体的内容包括状态码与数据,当出现错误时还包含错误信息,一般地,响应体如下:
- 正常响应
{
"code": 200,
"msg": "success",
"data": "hello everyone."
}
- 异常响应
{
"code": 500,
"msg": "/ by zero"
}
后续内容将在上一篇文章中 IDEA 项目的基础上,添加一个 common 包(具体的文件位置可以从下图中左侧项目结构获得)。
统一响应封装通过 RestControllerAdvice 注解,实现对请求的拦截,统一封装结果为 Result 。
@RestControllerAdvice(basePackages = "com.heartsuit.common.controller") public class ResultAdvice implements ResponseBodyAdvice
- Result.java
@Data @NoArgsConstructor @AllArgsConstructor public class Result{ private int code; private String msg; private T data; // Static methods public static Result success(T data) { return new Result (data, CodeMsg.SUCCESS); } public static Result success() { return new Result (CodeMsg.SUCCESS); } public static Result error(Integer code, String msg) { return new Result (code, msg); } public static Result error(CodeMsg codeMsg) { return new Result (codeMsg); } public static Result error(String msg) { CodeMsg codeMsg = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg); return new Result (codeMsg); } // Constructor private Result(Integer code, String msg) { this.code = code; this.msg = msg; } private Result(T data, CodeMsg codeMsg) { this.data = data; if (codeMsg != null) { this.code = codeMsg.getCode(); this.msg = codeMsg.getMsg(); } } private Result(CodeMsg codeMsg) { if (codeMsg != null) { this.code = codeMsg.getCode(); this.msg = codeMsg.getMsg(); } } }
- CodeMsg.java
@Getter
public class CodeMsg {
private int code;
private String msg;
// 通用的错误码
public static final CodeMsg SUCCESS =new CodeMsg(HttpStatus.OK.value(), "success");
public static final CodeMsg BAD_REQUEST = new CodeMsg(HttpStatus.BAD_REQUEST.value(), "请求无效");
public static final CodeMsg SERVER_ERROR = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务端异常");
public static final CodeMsg NO_HANDLER_FOUND = new CodeMsg(HttpStatus.NOT_FOUND.value(), "未找到对应资源");
public static final CodeMsg UNAUTHORIZED = new CodeMsg(HttpStatus.UNAUTHORIZED.value(), "未认证或登录状态过期");
public static final CodeMsg FORBIDDEN = new CodeMsg(HttpStatus.FORBIDDEN.value(), "未授权");
// 自定义错误码
public static final CodeMsg PARAMETER_ERROR = new CodeMsg(4000, "参数不正确!");
public static final CodeMsg CAPTCHA_EXPIRED = new CodeMsg(4001, "验证码不存在或已过期");
public static final CodeMsg CAPTCHA_INVALID = new CodeMsg(4002, "验证码错误");
public static final CodeMsg BAD_CREDENTIAL = new CodeMsg(4003, "用户名或密码错误");
public static final CodeMsg ACCOUNT_NOT_FOUND = new CodeMsg(4004, "账号不存在");
public static final CodeMsg ACCOUNT_NOT_ACTIVATED = new CodeMsg(4005, "账号未激活");
// 限流
public static final CodeMsg RATE_LIMIT = new CodeMsg(4006,"达到阈值啦!");
// 熔断
public static final CodeMsg DEGRADE = new CodeMsg(4007,"熔断啦!");
public static CodeMsg error(String msg){
return new CodeMsg(HttpStatus.BAD_REQUEST.value(),msg);
}
public CodeMsg(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
全局异常拦截
默认拦截所有异常(也可自定义异常进行封装),同样通过 RestControllerAdvice 注解,实现对异常响应的统一封装。
- RestExceptionHandler.java
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result exception(Exception e) {
log.error("Global exception: {}", null == e.getMessage() ? e.toString() : e.getMessage(), e);
return Result.error(CodeMsg.SERVER_ERROR.getCode(), null == e.getMessage() ? e.toString() : e.getMessage());
}
}
用于测试的Controller
@RestController
@RequestMapping("demo")
public class HelloController {
@GetMapping("hello")
public String hello() {
return "hello everyone.";
}
@GetMapping("error")
public Result error() {
int value = 8 / 0;
return Result.success(value);
}
}
小总结
至此,我们在基于 SpringBoot 的后端服务中完成了响应封装、异常拦截。下一篇我们的主角 TDengine 将闪亮登场: TDengine 集成 SpringBoot , MyBatisPlus 实现 ORM 与 基础的 CRUD 功能。
If you have any questions or any bugs are found, please feel free to contact me.
Your comments and suggestions are welcome!



