这篇文章主要介绍了Spring Boot 2.x如何统一返回值,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
创新互联公司服务项目包括庐阳网站建设、庐阳网站制作、庐阳网页制作以及庐阳网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,庐阳网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到庐阳省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
为什么要统一返回值
在我们做后端应用的时候,前后端分离的情况下,我们经常会定义一个数据格式,通常会包含code
,message
,data
这三个必不可少的信息来方便我们的交流,下面我们直接来看代码
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); } @Override public 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字节码。
下面,来看一下读取的工具类:
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(); }
下面我们可以去访问这个接口,看看会得到什么:
但是,现在问题又来了,因为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中导入这个模块
indi.viyoung.course viboot-common 1.0-SNAPSHOT
这里需要注意一点,必须保证你的切点的正确书写!!否则就会导致切点无效,同时需要在启动类中配置:
@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
,而是直接返回。
下面,我们修改一下test方法,让他抛出一个我们自定义的查询返回值为空的异常:
@RequestMapping("/test") public ReturnVO test(){ throw new NullResponseException(); }
下面,我们再来访问以下test接口:
可以看到,正如我们properties中定义的那样,我们得到了我们想要的消息。
感谢你能够认真阅读完这篇文章,希望小编分享的“Spring Boot 2.x如何统一返回值”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!
新闻标题:SpringBoot2.x如何统一返回值
标题来源:http://scyingshan.cn/article/isjghg.html