背景
本篇内容相对比较简单,不涉及具体的物联网技术,是作为后端工程师的基本操作,算是对基础框架的封装工作,我们使用 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<Object> {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof String) {
return objectMapper.writeValueAsString(Result.success(o));
}
if (o instanceof Result) {
return o;
}
return Result.success(o);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private int code;
private String msg;
private T data;
public static <T> Result<T> success(T data) {
return new Result<T>(data, CodeMsg.SUCCESS);
}
public static <T> Result<T> success() {
return new Result<T>(CodeMsg.SUCCESS);
}
public static <T> Result<T> error(Integer code, String msg) {
return new Result<T>(code, msg);
}
public static <T> Result<T> error(CodeMsg codeMsg) {
return new Result<T>(codeMsg);
}
public static <T> Result<T> error(String msg) {
CodeMsg codeMsg = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
return new Result<T>(codeMsg);
}
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();
}
}
}
@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<String> 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!