springboot项目统一封装返回值和异常处理(方式一)
为什么要统一返回值:
在我们做后端应用的时候,前后端分离的情况下,我们经常会定义一个数据格式,通常会包含code,message,data这三个必不可少的信息来方便我们的交流,下面我们直接来看代码package com.house.common;
import java.util.Properties;
import lombok.Data; /**
* 统一定义返回类
*
*/
@Data
public class ReturnVO { //获取程序当前路径下的文件
private static final Properties properties = ReadPropertiesUtil
.getProperties(System.getProperty("user.dir") + "/src/main/resources/response.properties"); /**
* 返回代码
*/
private String code; /**
* 返回信息
*/
private String message; /**
* 返回数据
*/
private Object data;
/**
* 默认构造,返回操作正确的返回代码和信息
*/
public ReturnVO() {
this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
} /**
* 构造一个返回特定代码的ReturnVO对象
* @param code
*/
public ReturnVO(ReturnCode code) {
this.setCode(properties.getProperty(code.val()));
this.setMessage(properties.getProperty(code.msg()));
} /**
* 默认值返回,默认返回正确的code和message
* @param data
*/
public ReturnVO(Object data) {
this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
this.setData(data);
} /**
* 构造返回代码,以及自定义的错误信息
* @param code
* @param message
*/
public ReturnVO(ReturnCode code, String message) {
this.setCode(properties.getProperty(code.val()));
this.setMessage(message);
} /**
* 构造自定义的code,message,以及data
* @param code
* @param message
* @param data
*/
public ReturnVO(ReturnCode code, String message, Object data) {
this.setCode(code.val());
this.setMessage(message);
this.setData(data);
} @Override
public String toString() {
return "ReturnVO{" +
"code='" + code + '\'' +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
在这里,我提供了几个构造方法以供不同情况下使用。代码的注释已经写得很清楚了,大家也可以应该看的比较清楚~
ReturnCode
细心的同学可能发现了,我单独定义了一个ReturnCode枚举类用于存储代码和返回的Message:
package com.house.common;
public enum ReturnCode {
/** 操作成功 */
SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"),
/** 操作失败 */
FAIL("FAIL_CODE", "FAIL_MSG"),
/** 空指针异常 */
NullpointerException("NPE_CODE", "NPE_MSG"),
/** 自定义异常之返回值为空 */
NullPointerException("NRE_CODE", "NRE_MSG");
ReturnCode(String value, String msg){
this.val = value;
this.msg = msg;
}
public String val() {
return val;
}
public String msg() {
return msg;
}
private String val;
private String msg;
}
这里,我并没有将需要存储的数据直接放到枚举中,而是放到了一个配置文件中response.properties,这样既可以方便我们进行相关信息的修改,并且阅读起来也是比较方便。
注意,这里的属性名和属性值分别与枚举类中的value和msg相对应,这样,我们才可以方便的去通过I/O流去读取。
SUCCESS_CODE = 1000
SUCCESS_MSG = success
NRE_CODE = 1021
NRE_MSG = exception001
(如不定义中文字段则跳过这步骤) 这里需要注意一点,如果你使用的是IDEA编辑器,需要修改以下的配置,这样你编辑配置文件的时候写的是中文,实际上保存的是ASCII字节码。

下面,来看一下读取的工具类:
package com.house.common; import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; public class ReadPropertiesUtil { public static Properties getProperties(String propertiesPath){
Properties properties = new Properties();
try {
InputStream inputStream = new BufferedInputStream(new FileInputStream(propertiesPath));
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return properties;
}
}
测试使用ReturnVO返回定义的格式:
@RequestMapping("/test")
public ReturnVO test(){
try {
//省略
//省略
} catch (Exception e) {
e.printStackTrace();
}
return new ReturnVO();
}
下面我们可以去访问这个接口,看看会得到什么:

但是,现在问题又来了,因为try...catch...的存在,总是会让代码变得重复度很高,一个接口你都至少要去花三到十秒去写这个接口,如果不知道编辑器的快捷键,更是一种噩梦。
我们只想全心全意的去关注实现业务,而不是花费大量的时间在编写一些重复的"刚需"代码上。
使用AOP进行全局异常的处理
(这里,我只是对全局异常处理进行一个简单的讲解,后面也就是下一节中会详细的讲述):
package com.house.common; import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; /**
* 统一封装返回值和异常处理
*
*/
@Slf4j
@Aspect
@Order(5)
@Component
public class ResponseAop { //获取程序当前路径下的文件
private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir")
+ "/src/main/resources/response.properties"); // 切点(在包下的所有controller以及他的子包)
//@Pointcut("execution(public * com.house.controller.*.controller..*(..))")
@Pointcut("execution(public * com.house.controller..*(..))")
public void httpResponse() {
} //环切
@Around("httpResponse()")
public ReturnVO handlerController(ProceedingJoinPoint proceedingJoinPoint) {
ReturnVO returnVO = new ReturnVO();
try {
//获取方法的执行结果
Object proceed = proceedingJoinPoint.proceed();
//如果方法的执行结果是ReturnVO,则将该对象直接返回
if (proceed instanceof ReturnVO) {
returnVO = (ReturnVO) proceed;
} else {
//否则,就要封装到ReturnVO的data中
returnVO.setData(proceed);
}
} catch (Throwable throwable) {
//如果出现了异常,调用异常处理方法将错误信息封装到ReturnVO中并返回
returnVO = handlerException(throwable);
}
return returnVO;
} //异常处理
private ReturnVO handlerException(Throwable throwable) {
ReturnVO returnVO = new ReturnVO();
//这里需要注意,返回枚举类中的枚举在写的时候应该和异常的名称相对应,以便动态的获取异常代码和异常信息
//获取异常名称的方法
String errorName = throwable.toString();
errorName = errorName.substring(errorName.lastIndexOf(".") + 1);
//直接获取properties文件中的内容
returnVO.setMessage(properties.getProperty(ReturnCode.valueOf(errorName).msg()));
returnVO.setCode(properties.getProperty(ReturnCode.valueOf(errorName).val()));
return returnVO;
}
}
<!--在使用切面注解@Aspect-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
下面我们来测试一下,访问我们经过修改后的编写的findAll接口:
@RequestMapping("/findAll")
public Object findAll(){
return userService.list();
}
PS:这里我将返回值统一为Object,以便数据存入data,实际类型应是Service接口的返回类型。如果没有返回值的话,那就可以new一个ReturnVO对象直接通过构造方法赋值即可。
关于返回类型为ReturnVO的判断,代码中也已经做了特殊的处理,并非存入data,而是直接返回。

下面,我们修改一下test方法,让他抛出一个我们自定义的查询返回值为空的异常:
@RequestMapping("/test")
public ReturnVO test(){
throw new NullResponseException();
}

下一篇,用springboot自带的注解@ControllerAdvice 实现统一异常处理。
springboot项目统一封装返回值和异常处理(方式一)的更多相关文章
- Springboot项目统一异常处理
Springboot项目统一异常处理 一.接口返回值封装 1. 定义Result对象,作为通用返回结果封装 2. 定义CodeMsg对象,作为通用状态码和消息封装 二.定义全局异常类 三.定义异常处理 ...
- SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!
大家好,我是飘渺. 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对Sp ...
- .NetCore Web Api 利用ActionFilterAttribute统一接口返回值格式
.Net Core 同 Asp.Net MVC一样有几种过滤器,这里不再赘述每个过滤器的执行顺序与作用. 在实际项目开发过程中,统一API返回值格式对前端或第三方调用将是非常必要的,在.NetCore ...
- 使用 ResponseBodyAdvice 拦截Controller方法默认返回参数,统一处理返回值/响应体
使用 @ControllerAdvice & ResponseBodyAdvice 拦截Controller方法默认返回参数,统一处理返回值/响应体 1.Controller代码 以下是Con ...
- ASP.NET Core搭建多层网站架构【11-WebApi统一处理返回值、异常】
2020/02/01, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[11-WebApi统一处理返回值.异常] 使用I ...
- (转)js弹窗&返回值(window.open方式)
本文转载自:http://hi.baidu.com/z57354658/item/5d5e26b8e9f42fa7ebba93d4 js弹窗&返回值(window.open方式) test.h ...
- SpringBoot项目中处理返回json的null值
在后端数据接口项目开发中,经常遇到返回的数据中有null值,导致前端需要进行判断处理,否则容易出现undefined的情况,如何便捷的将null值转换为空字符串? 以SpringBoot项目为例,SS ...
- SpringBoot 如何统一后端返回格式
在前后端分离的项目中后端返回的格式一定要友好,不然会对前端的开发人员带来很多的工作量.那么SpringBoot如何做到统一的后端返回格式呢?今天我们一起来看看. 为什么要对SpringBoot返回统一 ...
- asp.net core webapi 统一处理返回值、异常和请求参数验证
现在的开发模式很少用asp.net mvc一个项目直接操作界面和数据库了.大部分都使用前后端分离,更多的是为了让API支持移动端. 后端写webapi的时候必然需要和前端约定请求值和返回值的格式,如果 ...
- JAVAEE——SpringMVC第二天:高级参数绑定、@RequestMapping、方法返回值、异常处理、图片上传、Json交互、实现RESTful、拦截器
1. 课前回顾 https://www.cnblogs.com/xieyupeng/p/9093661.html 2. 课程计划 1.高级参数绑定 a) 数组类型的参数绑定 b) List类型的绑定 ...
随机推荐
- [ABC283Ex] Popcount Sum
Problem Statement Find the sum of popcounts of all integers between $1$ and $N$, inclusive, such tha ...
- 8、switch语句
1.switch语句:"开关" switch是一个条件语句,它计算表达式并将其与可能匹配的列表进行比较,并根据匹配执行代码块.它可以被认为是一种惯用的方式来写多个if else子句 ...
- SpringSecurity入门(SSM版)
1. 简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Sp ...
- Postgres服务器操作方法
切换用户 sudo su postgres psql postgres 查询当前postgres下的DB列表 \l 查看postgres下角色的详细信息(权限) \du 删除odoo角色 drop r ...
- 使用dtd定义元素
- MinIO客户端之ls
MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc ls 列出本地硬盘上的文件,命令如下: ./mc ls 控制台的输出,如下: [2023-12-14 23: ...
- Python——第二章:运算符
1. 算数运算 + - * / // % "//"除 "%"余 a = 20 b = 3 c = a // b d = a % b # 20 / 3 = ...
- Windows Server2016 默认使用英文输入法或默认使用中文输入法
1.确认是Server2016操作系统及以后版本 2.打开开始菜单"设置"--"时间和语言" 3.添加英文输入法(已存在可以跳过) 找到"区域与语言& ...
- OpenFeign:Spring Cloud声明式服务调用组件
OpenFeign:Spring Cloud声明式服务调用组件 问题总结 OpenFeign? Feign VS OpenFeign? OpenFeign实现远程服务调用? OpenFeign超时控制 ...
- super只能用在构造方法里面吗?
super关键字并不仅限于在构造方法中使用.在Java中,super关键字有两个主要的用途: 在子类的构造方法中调用父类的构造方法.这是super的一个常见用法,通常是在子类的构造方法的第一行使用,用 ...