Spring Boot 2.x(六):优雅的统一返回值

目录

  • 为什么要统一返回值
  • ReturnVO
  • ReturnCode
  • 使用ReturnVO
  • 使用AOP进行全局异常的处理
  • 云撸猫
  • 公众号

为什么要统一返回值

在我们做后端应用的时候,前后端分离的情况下,我们经常会定义一个数据格式,通常会包含codemessagedata这三个必不可少的信息来方便我们的交流,下面我们直接来看代码

ReturnVO

package indi.viyoung.viboot.util;import java.util.Properties;/*** 统一定义返回类** @author yangwei* @since 2018/12/20*/
public class ReturnVO {private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");/*** 返回代码*/private String code;/*** 返回信息*/private String message;/*** 返回数据*/private Object data;public Object getData() {return data;}public void setData(Object data) {this.data = data;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}/*** 默认构造,返回操作正确的返回代码和信息*/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);}@Overridepublic String toString() {return "ReturnVO{" +"code='" + code + '\'' +", message='" + message + '\'' +", data=" + data +'}';}
}

在这里,我提供了几个构造方法以供不同情况下使用。代码的注释已经写得很清楚了,大家也可以应该看的比较清楚~

ReturnCode

细心的同学可能发现了,我单独定义了一个ReturnCode枚举类用于存储代码和返回的Message:

package indi.viyoung.viboot.util;/*** @author yangwei* @since 2018/12/20*/
public enum ReturnCode {/** 操作成功 */SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"),/** 操作失败 */FAIL("FAIL_CODE", "FAIL_MSG"),/** 空指针异常 */NullpointerException("NPE_CODE", "NPE_MSG"),/** 自定义异常之返回值为空 */NullResponseException("NRE_CODE", "NRE_MSG");private 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;
}

这里,我并没有将需要存储的数据直接放到枚举中,而是放到了一个配置文件中,这样既可以方便我们进行相关信息的修改,并且阅读起来也是比较方便。

SUCCESS_CODE=2000
SUCCESS_MSG=操作成功FAIL_CODE=5000
FAIL_MSG=操作失败NPE_CODE=5001
NPE_MSG=空指针异常NRE_CODE=5002
NRE_MSG=返回值为空

注意,这里的属性名和属性值分别与枚举类中的value和msg相对应,这样,我们才可以方便的去通过I/O流去读取。

这里需要注意一点,如果你使用的是IDEA编辑器,需要修改以下的配置,这样你编辑配置文件的时候写的是中文,实际上保存的是ASCII字节码。
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZpX3lvdW5nXzk1,size_16,color_FFFFFF,t_70

下面,来看一下读取的工具类:

package indi.viyoung.viboot.util;import java.io.*;
import java.util.Iterator;
import java.util.Properties;/*** 读取*.properties中的属性* @author vi* @since 2018/12/24 7:33 PM*/
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;}
}

这里我直接写了一个静态的方法,传入的参数是properties文件的位置,这样的话,本文最初代码中的也就得到了解释。

    private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");

使用ReturnVO

    @RequestMapping("/test")public ReturnVO test(){try {//省略//省略}  catch (Exception e) {e.printStackTrace();}return new ReturnVO();}

下面我们可以去访问这个接口,看看会得到什么:
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZpX3lvdW5nXzk1,size_16,color_FFFFFF,t_70
但是,现在问题又来了,因为try...catch...的存在,总是会让代码变得重复度很高,一个接口你都至少要去花三到十秒去写这个接口,如果不知道编辑器的快捷键,更是一种噩梦。我们只想全心全意的去关注实现业务,而不是花费大量的时间在编写一些重复的"刚需"代码上。

使用AOP进行全局异常的处理

(这里,我只是对全局异常处理进行一个简单的讲解,后面也就是下一节中会详细的讲述)

/*** 统一封装返回值和异常处理** @author vi* @since 2018/12/20 6:09 AM*/
@Slf4j
@Aspect
@Order(5)
@Component
public class ResponseAop {private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");/*** 切点*/@Pointcut("execution(public * indi.viyoung.viboot.*.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;}
}

如果,我们需要在每一个项目中都可以这么去做,需要将这个类放到一个公用的模块中,然后在pom中导入这个模块

        <dependency><groupId>indi.viyoung.course</groupId><artifactId>viboot-common</artifactId><version>1.0-SNAPSHOT</version></dependency>

这里需要注意一点,必须保证你的切点的正确书写!!否则就会导致切点无效,同时需要在启动类中配置:

@ComponentScan(value = "indi.viyoung.viboot.*")

导入的正是common包下的所有文件,以保证可以将ResponseAop这个类加载到Spring的容器中。

下面我们来测试一下,访问我们经过修改后的编写的findAll接口:

    @RequestMapping("/findAll")public Object findAll(){return userService.list();}

PS:这里我将返回值统一为Object,以便数据存入data,实际类型应是Service接口的返回类型。如果没有返回值的话,那就可以new一个ReturnVO对象直接通过构造方法赋值即可。关于返回类型为ReturnVO的判断,代码中也已经做了特殊的处理,并非存入data,而是直接返回。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZpX3lvdW5nXzk1,size_16,color_FFFFFF,t_70
下面,我们修改一下test方法,让他抛出一个我们自定义的查询返回值为空的异常:

    @RequestMapping("/test")public ReturnVO test(){throw new NullResponseException();}

下面,我们再来访问以下test接口:
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZpX3lvdW5nXzk1,size_16,color_FFFFFF,t_70
可以看到,正如我们properties中定义的那样,我们得到了我们想要的消息。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

源码可以去github或者码云上进行下载,后续的例子都会同步更新。

云撸猫

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZpX3lvdW5nXzk1,size_16,color_FFFFFF,t_70

公众号

20181228073632641.jpg

如果帮到了你,请点击推荐让更多人看到~

转载于:https://www.cnblogs.com/viyoung/p/10188456.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/278572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Object defineProperty

Object defineProperty一、简介1. 属性表2.互斥性3. get、set的简单使用二、深入1.定义常量2. Object.preventExtensions() 禁止对象拓展(不可逆)3. Object.seal() 密封(不可逆)4. Object.freeze() 冻结(不可逆)三、应用一、简介 defineProperty可以详细的配置一个对象的属性的…

jhope代码分析以及网站结构

如下图所示&#xff0c;为Extjs部分代码提供的网页结构&#xff1a;网站看上去本来是这样的前端采用ExtJS&#xff0c;与后台的SpringMVCSpringHibernate进行数据交互。之前分析过登录的过程&#xff0c;不赘述在loginController处理登录返回结果的最后&#xff0c;如下语句也就…

Ubuntu下Authentication token manipulation error或者Authentication Failure解决办法

在Ubuntu18.04使用以下命令出现以下错误: 用passwd为新建用户或者root添加密码:Authentication token manipulation error 切换root用户出现Authentication Failure. 网上出现了大致两种方法: 第一种&#xff1a;用户文件和密码文件被保护&#xff0c;用chattr命令移除保护即可…

初学者:如何使用虚拟PC将Windows 7安装到虚拟机

Continuing in our series covering how to use Virtual PC, this week we’ll be showing you how to install Windows 7 into a virtual machine. It’s a very simple process, but here’s the step-by-step guide for beginners. 继续我们的系列文章&#xff0c;介绍如何使…

arcgis本地服务快速迁移到新机

情景 在本机或服务器发布了几十、几百个gis服务&#xff0c;当换电脑或者换服务器时不可能挨个找源文件重新发布服务&#xff0c;于是就想着既然是本地文件&#xff0c;一定可以拷贝过去的&#xff0c;经过一番搜索&#xff0c;结果如下: 方案一、迁移至新站点 新机站点创建…

js中 给json对象添加属性和json数组添加元素

json对象&#xff1a; 比如现在有一个json对象为jsonObj&#xff0c;需要给这个对象添加新的属性newParam&#xff0c;同时给newParam赋值为pre。做法如下&#xff1a; var jsonObj{param1:22,param2 :33}; 现在给jsonObj添加一个新的属性newParam jsonObj.newParam pre; 新的…

zabbix中php信息缺失之后的安装

安装php下enable bcmath和gettext &#xff08;在安装php时可以添加 --enable-bcmath --enable-gettext&#xff09;1,bcmath安装方法bcmath这个扩展在php源安装包压缩包中都是有的&#xff0c;需要重新编译一下才能够支持&#xff1b;cd php-5.2.7/ext/bcmath&#xff08;源…

极客大佬用什么电脑_极客特惠:笔记本电脑,高清电视和免费应用

极客大佬用什么电脑If you love new gear but not high prices then we’ve got some deals for you; grab some deeply discounted laptops, monitors and HDTVs, and free mobile apps in this week’s Geek Deals roundup. 如果您喜欢新设备&#xff0c;但不喜欢高价&#x…

Linux内核 TCP/IP、Socket参数调优

详见http://blog.csdn.net/u010009038/article/details/51917460转载于:https://blog.51cto.com/jack88/2063979

ppt插入html(用office而不是wps)

最近新get到的技能&#xff0c;在ppt里面插入html&#xff01;注意要用 Microsoft Office PowerPoint 才行&#xff0c;而不是wps&#xff0c;一定要先安装Microsoft Office PowerPoint再执行以下操作。 1、修改注册表的值&#xff0c;才能在PowerPoint中插入 Microsoft Web B…

如何使用SkyDrive的25 GB作为映射驱动器以方便访问

SkyDrive is an online storage system included in Windows Live, which gives you 25 GB of space that you can sync to your desktop. Here’s how to connect it to your Windows 7 computer as a mapped drive. SkyDrive是Windows Live中包含的一个在线存储系统&#xff…

SpringBoot+Mybatis 框架之 @SelectProvider注解方式搭建

之前搭建了Select标签来做SringBootMybatis的集成。这次使用SelectProvider标签的方式搭建一次。 一、搭建SpringBoot的项目 https://start.spring.io/自己配置SpringBoot的项目&#xff0c;点击“Generate Project”按钮就可以下载下来一个配置好的SpringBoot项目。 二、项目结…

程鑫峰:1.23日央行推行负利率政策,伦敦金后市行情解析

程鑫峰&#xff1a;1.23日央行推行负利率政策&#xff0c;伦敦金后市行情解析 QQ截图20180123153028.png   尽管美国政府关门闹剧刚刚结束&#xff0c;但交易员、投资者和策略师对于美元的前景依然不太乐观。美国货币政策对美元的影响力减弱可能是全球通货再膨胀交易的另一个…

从购买域名到nginx,flask搭建自己的网站

搭建一个只属于自己的网站? 一、注册域名&#xff08;可选*&#xff09; 1.注册阿里云账号 网址&#xff1a;登录&#xff08;注册&#xff09; 2.购买域名&#xff1a;阿里云域名注册 有一元域名、免费域名等。 购买过程中需要创建信息模板&#xff08;必须完成邮箱真实…

alexa语音实现_如何通过语音删除Alexa录音

alexa语音实现Amazon亚马孙Amazon is rolling out new privacy features today for Alexa. In addition to an educational “privacy hub,” the company lets you delete your stored recordings by voice. But it’s off by default; you’ll need to flip a switch. 亚马逊…

linux如何查看所有的用户(user)、用户组(group)、密码(password/passwd)

linux如何查看所有的用户和组信息_百度经验https://jingyan.baidu.com/article/a681b0de159b093b184346a7.html linux添加用户、用户组、密码_百度经验https://jingyan.baidu.com/article/335530da8b7e0419cb41c3e5.html 给用户开通sudo权限 xxx is not in the sudoers file.Th…

angular之两种路由

安装angular npm install -g angular/cli ng new myapp ng g component componentName 自带路由 引入&#xff1a;angular-route.js <div ng-controllerctr1><a href#home>首页</a> <a href#mine>我的</a> <div ng-view></div><d…

用scrapy框架写爬虫

爬虫可以发送给引擎的两种请求&#xff1a; # 1、url&#xff1a;# &#xff08;爬虫&#xff09;yield scrapy.Request -> 引擎 -> 调度器&#xff08;发送给调度器入队&#xff09; -> 引擎&#xff08;调度器出队请求于引擎&#xff09;# -> 下载器&#xff08;…

audacity_如何在Audacity中快速编辑多个文件

audacityGot a bunch of files that need to be edited the same way? You can automate the process to save time and effort using Audacity’s Chain feature and modify tons of files at the same time. 有一堆需要以相同方式编辑的文件&#xff1f; 您可以使用Audacity…

通过api管理grafana

1. 生成api key 参考&#xff1a; http://docs.grafana.org/http_api/auth/ 2.点击添加后&#xff0c;生成了个获取一个deshboards的api样例 3.放到linux上运行测试&#xff0c;结果成功返回。 4. 有些api并不支持使用api key 来连接&#xff0c;如下图中的搜索用户接口&#x…