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类型的绑定 ...
随机推荐
- 主界面(零基础适合小白)基础javaweb前端项目实战【包含增删改查,mysql】三
首先编写sp文件(index.jsp) <%@ page contentType="text/html;charset=UTF-8" language="java& ...
- 最好用的oa办公系统?
OA办公系统是一种集成办公自动化.协同办公.信息管理等功能于一体的软件系统,旨在提高办公效率,优化流程管理,提供更好的团队协作和信息共享.下面将详细介绍几个目前市场上认为较为优秀的OA办公系统. 一. ...
- JSR223取样器详解
相比于BeanShell 取样器,JSR223取样器具有可大大提高性能的功能(编译)如果需要,一定要使用JSR223取样器编写脚本是更好的选择!!! 属性描述名称:显示的此取样器的描述性名称,可自定义 ...
- Vue3+Vite+ElementPlus管理系统常见问题
本文本记录了使用 Vue3+Vite+ElementPlus 从0开始搭建一个前端工程会面临的常见问题,没有技术深度,但全都是解决实际问题的干货,可以当作是问题手册以备后用.本人日常工作偏后端开发,因 ...
- uniapp---wap2app去掉系统自带的导航栏
在用uniapp进行将wap站转化为app的时候,默认打包后的文件,带有系统的导航栏,下面是去除的办法: 第一步:找到 sitemap.json 设置 titleNView为false: 第二步:在 ...
- Hive select查询语句
创建表 CREATE TABLE t_usa_covid19( count_date string, county string, state string, fips int, cases int, ...
- The second day learning summary
1.什么是接口测试? 接口测试是测试系统组件间接口的一种测试.接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点,定义特定的交互点,然后通过这些交互点来,通过一些特殊的规则也就是协议,来 ...
- Redis全文搜索教程之创建索引并关联源数据
Redis 全文搜索是依赖于 Redis 官方提供的 RediSearch 来实现的.RediSearch 提供了一种简单快速的方法对 hash 或者 json 类型数据的任何字段建立二级索引,然后就 ...
- 企业u盘禁止访问如何解锁
如果您遇到了U盘禁止访问的问题,可能是由于系统设置.安全策略或第三方工具导致的.以下是一些可能的解锁方法,具体的操作可能因具体情况而异: 管理员权限: 确保您有足够的管理员权限来解锁U盘.有时,系统管 ...
- 【C#】【DateTime】获取当前时间的前一天或者后一天方法学习
假期懈怠了一阵子,因为工作环境没有网络,随即记录下当时的问题: 1.关于DateTime.Now(2023/10/07)的前一天的时间(2023/10/06),想要通过ToString转换成字符串后除 ...