栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

物联网设备数据流转之搭建后端服务框架:SpringBoot统一响应封装,全局异常拦截

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

物联网设备数据流转之搭建后端服务框架:SpringBoot统一响应封装,全局异常拦截

背景

本篇内容相对比较简单,不涉及具体的物联网技术,是作为后端工程师的基本操作,算是对基础框架的封装工作,我们使用 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 {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class> aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class> 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);
    }
}
 
  • 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!

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号