前言

缘由

博友的需求就是我最大的动力

博友一说话,本狗笑哈哈。博友要我写啥,我就写啥

特来一篇关于SpringBoot接口返回结果及异常统一处理,虽说封不封装都能用,但咱后端也得给前端小姐姐留个好印象不是。项目前后端分离,规范的数据传输格式,让REST风格的API具有简单、易读、易用的特点。不仅代码优美,也可以让带刀的前端小姐姐变得更漂亮。以下例子参考多个实际项目,最终总结来跟大家进行分享,大佬勿喷。


主要目标

实现2大重点

1. 统一接口返回结果
2. 配置全局异常处理

正文

一.统一接口返回结果

前端接口请求后台端,后端将返回结果统一封装。提高交互的规范性通用性,也提高了前后端联调效率。前端根据规范格式返回结构体进行统一映射处理,就避免一个接口一个返回格式的问题。

1.统一封装结果包含如下参数

  • 状态码:code
  • 状态信息:status
  • 返回信息:message
  • 数据:data

2.统一封装结果包含如下方法

  • 全参数方法
  • 成功返回(无参)
  • 成功返回(枚举)
  • 成功返回(状态码+返回信息)
  • 成功返回(返回信息 + 数据)
  • 成功返回(状态码+返回信息+数据)
  • 成功返回(数据)
  • 成功返回(返回信息)
  • 失败返回(无参)
  • 失败返回(枚举)
  • 失败返回(状态码+返回信息)
  • 失败返回(返回信息+数据)
  • 失败返回(状态码+返回信息+数据)
  • 失败返回(数据)
  • 失败返回(返回信息)

3.ResponseResult封装返回结果代码

package net.javadog.common.result;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.javadog.common.enums.HttpStatusEnum; /**
* 返回结果集
*
* @author javadog
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("统一结果集处理器")
public class ResponseResult<T> { /**
* 状态码
*/
@ApiModelProperty(value = "状态码")
private Integer code; /**
* 状态信息
*/
@ApiModelProperty(value = "状态信息")
private Boolean status; /**
* 返回信息
*/
@ApiModelProperty(value = "返回信息")
private String message; /**
* 数据
*/
@ApiModelProperty(value = "数据")
private T data; /**
* 全参数方法
*
* @param code 状态码
* @param status 状态
* @param message 返回信息
* @param data 返回数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
private static <T> ResponseResult<T> response(Integer code, Boolean status, String message, T data) {
ResponseResult<T> responseResult = new ResponseResult<>();
responseResult.setCode(code);
responseResult.setStatus(status);
responseResult.setMessage(message);
responseResult.setData(data);
return responseResult;
} /**
* 全参数方法
*
* @param code 状态码
* @param status 状态
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
private static <T> ResponseResult<T> response(Integer code, Boolean status, String message) {
ResponseResult<T> responseResult = new ResponseResult<>();
responseResult.setCode(code);
responseResult.setStatus(status);
responseResult.setMessage(message);
return responseResult;
} /**
* 成功返回(无参)
*
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success() {
return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), null);
} /**
* 成功返回(枚举参数)
*
* @param httpResponseEnum 枚举参数
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(HttpStatusEnum httpResponseEnum) {
return response(httpResponseEnum.getCode(), true, httpResponseEnum.getMessage());
} /**
* 成功返回(状态码+返回信息)
*
* @param code 状态码
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(Integer code, String message) {
return response(code, true, message);
} /**
* 成功返回(返回信息 + 数据)
*
* @param message 返回信息
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(String message, T data) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, message, data);
} /**
* 成功返回(状态码+返回信息+数据)
*
* @param code 状态码
* @param message 返回信息
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(Integer code, String message, T data) {
return response(code, true, message, data);
} /**
* 成功返回(数据)
*
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(T data) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), data);
} /**
* 成功返回(返回信息)
*
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(String message) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, message, null);
} /**
* 失败返回(无参)
*
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail() {
return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), null);
} /**
* 失败返回(枚举)
*
* @param httpResponseEnum 枚举
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(HttpStatusEnum httpResponseEnum) {
return response(httpResponseEnum.getCode(), false, httpResponseEnum.getMessage());
} /**
* 失败返回(状态码+返回信息)
*
* @param code 状态码
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(Integer code, String message) {
return response(code, false, message);
} /**
* 失败返回(返回信息+数据)
*
* @param message 返回信息
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(String message, T data) {
return response(HttpStatusEnum.ERROR.getCode(), false, message, data);
} /**
* 失败返回(状态码+返回信息+数据)
*
* @param code 状态码
* @param message 返回消息
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(Integer code, String message, T data) {
return response(code, false, message, data);
} /**
* 失败返回(数据)
*
* @param data 数据
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(T data) {
return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), data);
} /**
* 失败返回(返回信息)
*
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(String message) {
return response(HttpStatusEnum.ERROR.getCode(), false, message, null);
}
}

4.HttpStatusEnum返回结果代码

package net.javadog.common.enums;

import lombok.Getter;

/**
* Http状态返回枚举
*
* @author javadog
**/
@Getter
public enum HttpStatusEnum {
/**
* 操作成功
*/
SUCCESS(200, "操作成功"),
/**
* 对象创建成功
*/
CREATED(201, "对象创建成功"),
/**
* 请求已经被接受
*/
ACCEPTED(202, "请求已经被接受"),
/**
* 操作已经执行成功,但是没有返回数据
*/
NO_CONTENT(204, "操作已经执行成功,但是没有返回数据"),
/**
* 资源已被移除
*/
MOVED_PERM(301, "资源已被移除"),
/**
* 重定向
*/
SEE_OTHER(303, "重定向"),
/**
* 资源没有被修改
*/
NOT_MODIFIED(304, "资源没有被修改"),
/**
* 参数列表错误(缺少,格式不匹配)
*/
BAD_REQUEST(400, "参数列表错误(缺少,格式不匹配)"),
/**
* 未授权
*/
UNAUTHORIZED(401, "未授权"),
/**
* 访问受限,授权过期
*/
FORBIDDEN(403, "访问受限,授权过期"),
/**
* 资源,服务未找到
*/
NOT_FOUND(404, "资源,服务未找!"),
/**
* 不允许的http方法
*/
BAD_METHOD(405, "不允许的http方法"),
/**
* 资源冲突,或者资源被锁
*/
CONFLICT(409, "资源冲突,或者资源被锁"),
/**
* 不支持的数据,媒体类型
*/
UNSUPPORTED_TYPE(415, "不支持的数据,媒体类型"),
/**
* 系统内部错误
*/
ERROR(500, "系统内部错误"),
/**
* 接口未实现
*/
NOT_IMPLEMENTED(501, "接口未实现"),
/**
* 系统警告消息
*/
WARN(601,"系统警告消息"); private final Integer code;
private final String message; HttpStatusEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}

5.SysLoginController实操调试

/**
* 登录验证
*
* @author javadog
*/
@RestController
public class SysLoginController { @Resource
private SysLoginService loginService; /**
* 登录方法
*
* @param loginRequest 登录信息
* @return 结果
*/
@PostMapping("/login")
public ResponseResult login(@RequestBody LoginRequest loginRequest) {
// 生成令牌
String token = loginService.login(loginRequest.getUsername(), loginRequest.getPassword());
return ResponseResult.success(token);
} }


二.配置全局异常处理

在使用上方统一返回结果的加持下,规范的同时也不可避免程序异常情况。因此我们必须提前定义一个统一全局异常来捕获这些异常信息,并将其当作一种结果返回给控制层,友好的处理异常信息。

1.全局异常处理注解

@RestControllerAdvice

@RestControllerAdvice什么是?

  • @RestControllerAdvice注解是Spring MVC和Spring Boot应用程序中用于定义全局异常处理类的注解,它是@ControllerAdvice注解的特殊版本,是一个组合注解,由@ControllerAdvice、@ResponseBody组成

  • @ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个组件,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法

@RestControllerAdvice有什么特点?

  • 注解@RestControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上
  • @RestControllerAdvice注解将作用于所有注解了@RequestMapping的控制器的方法上
  • @ExceptionHandler:用于指定异常处理方法,与@RestControllerAdvice配合使用时,用于全局处理控制器里的异常
  • @InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
  • @ModelAttribute:本来作用是绑定键值对到Model中,当与@ControllerAdvice配合使用时,可以让全局的@RequestMapping都能获得在此处设置的键值对

2.@ExceptionHandler常用异常拦截

  • 权限校验异常:AccessDeniedException(spring-security中异常)
  • 请求方式不支持:HttpRequestMethodNotSupportedException
  • 业务异常:ServiceException(自己业务定义异常)
  • 拦截未知的运行时异常:RuntimeException
  • 系统异常:Exception
  • 自定义验证异常:BindException
  • 自定义验证异常:MethodArgumentNotValidException

3.全局异常处理代码

package net.javadog.common.exception;

import cn.hutool.core.util.ObjectUtil;
import net.javadog.common.enums.HttpStatusEnum;
import net.javadog.common.result.ResponseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; /**
* 异常处理 配置
*
* @author javadog
*/
@RestControllerAdvice
public class GlobalException { private static final Logger log = LoggerFactory.getLogger(GlobalException.class); /**
* 权限校验异常
*/
@ExceptionHandler(AccessDeniedException.class)
public ResponseResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
return ResponseResult.fail(HttpStatusEnum.FORBIDDEN.getCode(), HttpStatusEnum.FORBIDDEN.getMessage());
} /**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return ResponseResult.fail(e.getMessage());
} /**
* 业务异常
*/
@ExceptionHandler(ServiceException.class)
public ResponseResult handleServiceException(ServiceException e) {
log.error(e.getMessage(), e);
Integer code = e.getCode();
return ObjectUtil.isNotNull(code) ? ResponseResult.fail(code, e.getMessage()) : ResponseResult.fail(e.getMessage());
} /**
* 拦截未知的运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public ResponseResult handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return ResponseResult.fail(e.getMessage());
} /**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public ResponseResult handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生系统异常.", requestURI, e);
return ResponseResult.fail(e.getMessage());
} /**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public ResponseResult handleBindException(BindException e) {
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return ResponseResult.fail(message);
} /**
* 自定义验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(), e);
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return ResponseResult.fail(message);
} }

4.全局异常处理实操调试

总结

本文通过多个SpringBoot实际项目进行归纳整理,从统一接口返回结果配置全局异常处理两个方面出发,介绍如何优雅的封装规范后端接口输出,详细刨析@RestControllerAdvice和@ExceptionHandler注解及使用方式,增加后端服务健壮性和与前端对接规范性,希望由此化繁为简,能够帮到博友分毫。


猜你想问

如何与狗哥联系进行探讨

关注公众号【JavaDog程序狗】

公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹。

此群优势:

  1. 技术交流随时沟通
  2. 任何私活资源免费分享
  3. 实时科技动态抢先知晓
  4. CSDN资源免费下载
  5. 本人一切源码均群内开源,可免费使用
2.踩踩狗哥博客

javadog.net

大家可以在里面留言,随意发挥,有问必答


猜你喜欢

文章推荐

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!

【ChatGPT】手摸手,带你玩转ChatGPT

【ChatGPT】SpringBoot+uniapp+uview2对接OpenAI,带你开发玩转ChatGPT


【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅的更多相关文章

  1. springboot接口返回封装与异常控制

    首先,返回有两个状态,status和code status标识response的状态,有2个值:0成功,-1服务错误. code跟业务有关,可以有各种数值,99999服务未知异常,10000参数异常, ...

  2. django学习-17.如何提供一个规范的接口返回值

    目录结构 1.前言 2.进行实际的一个完整流程操作 2.1.第一步:编写一个用于查询用户数据的视图函数 2.2.第二步:编写对应的一个url匹配规则 2.3.第三步:启动django项目[hellow ...

  3. springboot 接口返回数据时 net.sf.json.JSONNull["empty"]) 异常

    @ResetController返回数据时出现异常 Could not write JSON: Object is null; nested exception is com.fasterxml.ja ...

  4. 第3章 springboot接口返回json 3-1 SpringBoot构造并返回一个json对象

    数据的使用主要还是以JSON为主,我们不会去使用XML. 这个时候我们先不使用@RestController,我们使用之前SpringMVC的那种方式,就是@Controller.  @Respons ...

  5. SpringBoot接口返回去掉空字段

    返回的接口中存在值为null或者空的字段过滤掉 @Configuration public class JacksonConfig { @Bean @Primary @ConditionalOnMis ...

  6. 第3章 springboot接口返回json 3-2 Jackson的基本演绎法

    @JsonIgnore private String password; @JsonFormat(pattern="yyyy-MM-dd hh:mm:ss a",locale=&q ...

  7. SpringBoot统一处理返回结果和异常情况

    如果文章有帮助到你,还请点个赞或留下评论 原因 在springboot项目里我们希望接口返回的数据包含至少三个属性: code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功. messa ...

  8. SpringBoot接口 - 如何优雅的对接口返回内容统一封装?

    在以SpringBoot开发Restful接口时,统一返回方便前端进行开发和封装,以及出现时给出响应编码和信息.@pdai SpringBoot接口 - 如何优雅的对接口返回内容统一封装? RESTf ...

  9. Springboot项目全局异常统一处理

    转自https://blog.csdn.net/hao_kkkkk/article/details/80538955 最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项 ...

  10. SpringBoot接口 - 如何优雅的写Controller并统一异常处理?

    SpringBoot接口如何对异常进行统一封装,并统一返回呢?以上文的参数校验为例,如何优雅的将参数校验的错误信息统一处理并封装返回呢?@pdai 为什么要优雅的处理异常 如果我们不统一的处理异常,经 ...

随机推荐

  1. 免费获取最新WebStorm激活码,永久激活WebStorm

    在互联网上,目前还没有查询到一篇写得比较详细的WebStorm安装和激活教程.今天我将使用WebStorm最新2023年版本,从下载到安装以及创建项目带大家完整的走一遍. 分享的 WebStorm 2 ...

  2. [Qt开发]一口气搞懂串口通信

    好多小鳄鱼 一.关于串口通信: Qt的确有自己的串口通信类,就是QSerialPort,但是我们在使用过程中因为要更加定制化的使用串口通信类减小开发的难度,所以我们会提供一个串口通信类,也就是这个Se ...

  3. 手动删除了Linux下syslog--/var/log/messages怎么办?

    引言 Linux小白很容易犯得一个错误就是:查看日志的时候,尤其是系统日志,由于日志太多,把系统日志手动删除了.也就是把/var/log/messages文件删除了,而不是删除文件的内容.直接删除文件 ...

  4. 【后端面经】MySQL主键、唯一索引、联合索引的区别和作用

    目录 0. 简介 1. 主键 2. 唯一索引 3. 联合索引 4. 索引对数据库操作的影响 5. 其他索引 5.1 普通索引 5.2 全文索引 5.3 前缀索引 6. 总结 7. 参考资料 0. 简介 ...

  5. Spark架构与运行流程

    1. 阐述Hadoop生态系统中,HDFS, MapReduce, Yarn, Hbase及Spark的相互关系. 2. Spark已打造出结构一体化.功能多样化的大数据生态系统,请简述Spark生态 ...

  6. 2-SQL

    1. SQL 全称 Structured Query Language,结构化查询语言.操作关系型数据库的编程语言,定义了 一套操作关系型数据库统一标准 . 2. SQL 通用语法 1). SQL 语 ...

  7. 基于生成式预训练Transformer的跨语言文本摘要与情感分析

    目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成 ...

  8. GPT3的应用领域:机器翻译、文本生成、文本摘要

    目录 1. 引言 2. 技术原理及概念 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成与测试 4. 应用示例与代码实现讲解 4.1 机器翻译 4.2 文 ...

  9. PostgreSQL 性能优化: 等待事件

    等待事件 等待事件是 PostgreSQL 的重要优化工具.当您能查明会话为什么在等待资源以及会话在做什么时,您就能更好地减少瓶颈.您可以使用本节中的信息来查找可能的原因和纠正措施. 目录 等待事件概 ...

  10. BLOB-CLOB 处理成String (*)

    实体类中的写法: --实体类对应的类型为byte[] (clob为char[]). /* byte[] blob = commonService.getPersonImage(bean.getIdCa ...