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,一经查实,立即删除!

相关文章

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;结果如下: 方案一、迁移至新站点 新机站点创建…

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

极客大佬用什么电脑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…

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项目。 二、项目结…

从购买域名到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. 亚马逊…

用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…

vue项目将token存在(vuex)store和localstorage中

文章目录一、准备工作和token1、准备工作2、介绍token用法二、创建storage&#xff0c;store&#xff0c;request1、src目录&#xff1a;2、封装storage&#xff08;可选&#xff09;3、创建store4、创建request三、配置代理&#xff0c;封装路由router、设置路由守卫&#xff…

安卓手电筒_将价值10美元的手电筒砍入超高亮高级灯中

安卓手电筒If you’re looking for a bright flashlight without paying an arm and a leg this simple hack modifies a cheap $10 flashlight to be as bright as a $95 one. 如果您要寻找一个明亮的手电筒而又不用付胳膊和腿&#xff0c;这个简单的技巧就可以将便宜的10美元…

初识 scrapy 框架 - 安装

前面豆子学习了基本的urllib的模块&#xff0c;通过这个模块可以写一些简单的爬虫文件。如果要处理大中型的爬虫项目&#xff0c;urllib就显得比较low了&#xff0c;这个时候可以使用scrapy框架来实现&#xff0c;很多基本的处理在scrapy里面已经做好了。 首先来安装一下。推荐…

Vue使用Vuex一步步封装并使用store

文章目录一、安装Vuex依赖二、一步步封装store1. main.js中全局引入store仓库&#xff08;下一步创建&#xff09;2. this.$store3. this.$store.state4. this.$store.getters&#xff08;this. $store.state的升级&#xff09;5. this.$store.commit(mutations)6. this.$store…

linux自学(四)之开始centos学习,网络配置

上一篇&#xff1a;linux自学&#xff08;三&#xff09;之开启虚拟机 安装好镜像之后&#xff0c;重启之后需要登录&#xff0c;我这里直接是root账号直接登录的&#xff0c;注意&#xff1a;输入密码的时候不显示。 之后输入ifconfig最常用的命令来查看网卡信息&#xff0c;出…

k8s extender_Windows Home Server的Drive Extender的9种选择

k8s extenderNow that Microsoft has officially killed off the best part about Windows Home Server what can you do? Here are some alternatives for drive extender that you can use if you want to build a WHS of your own. 既然Microsoft正式取消了Windows Home Se…

为什么element的el-backtop会不管用,来看这里

<template>Scroll down to see the bottom-right button.<el-backtop target".page-component__scroll .el-scrollbar__wrap"></el-backtop> </template>把target指向你要产生“回到顶部”按钮的组件&#xff0c; 这个组件一定要是产生滚动条…