一、前言、背景

在如今前后端分离的时代,后端已经由传统的返回view视图转变为返回json数据,此json数据可能包括返回状态、数据、信息等......因为程序猿的习惯不同所以返回json数据的格式也各有千秋;此时迫切需要一个需求----将后台返回的数据再封装起来统一返回一个标准的类型供前端程序猿调用。

SpringBoot框架中,它已经给我们封装了一个标准的类型ResponseEntity,但是框架考虑的很多,很是冗余,因此我们需要自己动手编写适合自己使用的标准 我把他称之为R类型。循序渐进

二、返回的统一格式

在开发中 我常用 code 表示状态码、message表示返回的提示信息、data表示返回的具体数据

{
"code": 数字, //响应码
"message": 字符串, //返回消息
"data": object //返回数据
}

三、创建统一返回类

1. 创建标准返回类

// 统一结果返回类
@Data
@AllArgsConstructor
public class R {
//标识返回的状态码
private Integer code;
//标识返回的信息
private String message;
//标识返回的数据
private Object data; //私有化,防止new
private R() { } //成功
public static R ok(Object data, String message) {
return new R(200, message, data); //code 也可以使用字典管理 下面会谈到
} //成功返回 重载 message没有特别要求
public static R ok(Object data) {
return R.ok(data, "success"); //message 也可以使用字典管理 下面会谈到
} // 失败
public static R error( Integer code, String message) {
return new R(code, message, "");
}
}

牛刀小试返回结果

{
"code": 200,
"message": "成功",
"data": {
"id": 1,
"account": "qd666",
"passWord": "123456"
}
}

2. 统一字典管理

在上述成功的案例中,code 的值为200,而在失败中就不止这一种情况 所以需要改进

新建RConstants接口 统一维护

//返回常量
public interface RConstants {
Integer FAIL_CODE=201;
String FAIL_MESSAGE="查询失败";
//......
}

调用

 return R.error(RConstants.FAIL_CODE, RConstants.FAIL_MESSAGE); //201,查询失败

结果

{
"code": 201,
"message": "查询失败",
"data": ""
}

3. 枚举类型匹配

在上述接口中,我们发现,如果一个code 如果要对应message的话,需要创建大量的自定义常量,非常麻烦,这时我们可以改变其为枚举类型使我们的代码更加简介 但是如果只有一个属性的话,使用枚举就多此一举了

创建RHttpStatusEnum 枚举

public enum RHttpStatusEnum {

    //举个栗子 查询失败与登录失败
QUERY_USER_FAIL(201, "查询失败"),
LOGIN_USER_FAIL(202, "登录失败"); final int code;
final String message;
RHttpStatusEnum(int code, String message) {
this.code = code;
this.message = message;
}
//生成get方法 已经赋值了所以不需要set方法
}

调用

return R.error(RHttpStatusEnum.QUERY_USER_FAIL.getCode(),
RHttpStatusEnum.QUERY_USER_FAIL.getMessage());

当我们使用了枚举之后,发现在调用R类时比较复杂 我们可以改变R类的error方法


4. 简化R类方法

修改error方法

    // 失败
public static R error(RHttpStatusEnum httpStatusEnum) {
return new R(httpStatusEnum.getCode(),httpStatusEnum.getMessage(),"");
}

调用 参考SpringBootHttpStatus

return R.error(RHttpStatusEnum.QUERY_USER_FAIL);

ok !写道这里就发现我们定义的这个标准格式已经非常完美了 满足日常开发的使用了 但同时也会有丝丝缺点,因为这个R类把后端返回的数据限制住了,开发人员必须在实际代码中都要返回这个R类,降低了扩展性 。

解决方案: 在开发之中,程序猿想要随心所欲的返回任何的数据,我们只需使用R类对其封装一层即可! 利用Spring的后置机制可以实现该要求。 个人觉得不在包装也是很好的,依据自己的情况而定!

四、封装R类

可以使用spring提供的结果拦截增强处理机制来解决这个问题,如下:

采用springboot提供的 ResponseBodyAdvicel处理即可。

ResponseBodyAdvice的作用是:拦截Controller方法的返回值,统一处理返回值到响应体中,一般来做response的统一格式,加密,签名等。

  • 实现ResponseBodyAdvice接口,并扫描包名
@ControllerAdvice(basePackages = "com.qd.springboot") //扫描包
public class ResultResponseHandler implements ResponseBodyAdvice<Object> { /**
* 是否支持advice功能,true是支持、false是不支持
*
* @param methodParameter
* @param aClass
* @return
*/
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
} //o = controller方法的返回值
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
//如果返回的是string会默认调用string的处理器直接返回
if (o instanceof String) {
return JSON.toJSONString(R.ok(o));
}else if(o instanceof R){
return o;
}
return R.ok(o);
}
}
  • 导入需要的依赖
        <!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
  • R类 如果没有太多的对应关系,直接用接口实现即可
@Data
@AllArgsConstructor
public class R {
//标识返回的状态码
private Integer code;
//标识返回的信息
private String message;
//标识返回的数据
private Object data; //私有化,防止new
private R() {
} //成功
public static R ok(Object data, String message) {
return new R(200, message, data);
} //成功
public static R ok(Object data) {
return R.ok(data, "success");
} // 失败
public static R error(Integer code, String message) {
return new R(code, message, "");
}
}
  • 字典管理
public interface RConstants {
Integer FAIL_CODE=201;
String FAIL_MESSAGE="查询失败";
//......
}

这样设置后,需要捕获程序运行中的异常,对于不正确的请求,我们主动抛出异常,然后统一去捕获,最后调用R类error方法统一返回错误信息

  • GlobalExceptionHandler 全局异常
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler { @ExceptionHandler(value = RuntimeException.class)
@ResponseBody
public Object exceptionHandler1(RuntimeException e) {
log.error("异常类型:{}--异常信息:{}", e.getClass(), e.getMessage());
//code状态码可在字典中定义
return R.error(201, e.getMessage());
} //数据校验
@ExceptionHandler(value = ConstraintViolationException.class)
public Object ViolationExceptions(ConstraintViolationException e) {
log.error("异常类型:{}--异常信息:{}", e.getClass(), e.getMessage());
String ex = e.getMessage();
String message = null;
//判断是否多参数错误 是:一个个返回;否:返回
if (ex.contains(",")) {
message = ex.substring(ex.indexOf(":") + 1, ex.indexOf(","));
} else {
message = ex.split(":")[1].toString();
}
return R.error(201, message);
} //其他的异常.... }
  • controller或者service 判断标志 主动抛出异常
    @GetMapping("user/id/{id}")
public User queryUserByID(@PathVariable("id") Integer id) {
if ("2".equals(id)) {
throw new RuntimeException(RConstants.FAIL_MESSAGE);
}
return userService.queryUserById(id);
}

到此,就学习的差不多了


The End~~

java统一返回标准类型的更多相关文章

  1. 使用Java泛型返回动态类型

    返回一个指定类型的集合,并且clazz必须继承IGeoLog对象或者是其本身 <T extends IGeoLog> List<T> getLogListSql(Class&l ...

  2. springboot之全局处理统一返回

    springboot之全局处理统一返回 简介 在REST风格的开发中,避免通常会告知前台返回是否成功以及状态码等信息.这里我们通常返回的时候做一次util的包装处理工作,如:Result类似的类,里面 ...

  3. 阿里官方Java代码规范标准《阿里巴巴Java开发手册 终极版 v1.3.0》

    终极版 v1.3.0 2017年开春之际,阿里诚意献上重磅大礼:<阿里巴巴Java开发手册>,首次公开阿里官方Java代码规范标准.这套Java统一规范标准将有助于提高行业编码规范化水平, ...

  4. 阿里官方Java代码规范标准《阿里巴巴Java开发手册》下载

    https://bbs.aliyun.com/read/306592.html?page=e 2017年开春之际,诚意献上重磅大礼:阿里巴巴Java开发手册,首次公开阿里官方Java代码规范标准. 这 ...

  5. JDBC数据类型、Java数据类型、标准sql类型

    本概述是从<JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference>这本书中摘引来的.JavaSoft ...

  6. Java协变返回类型

    今天看到句话:“支持重写方法时返回协变类型”. 那么什么事协变类型?在网上找了找资料,大体上明白了. Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方 ...

  7. java.lang.IllegalArgumentException异常 返回值类型的问题

    java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return usi ...

  8. Java 同时返回多个不同类型的方法

    Java 同时返回多个不同类型的方法 2016年12月02日 16:05:07 FXBStudy 阅读数:10045   前言:虽然对于这种需求不常用,且比较冷门,但是还是有其存在的价值,再次做一下整 ...

  9. JAVA是否允许返回值类型不同的重载overload或覆盖override

    在看<Thinking in java>的时候,看到子类的方法和父类的方法名字相同,但是返回值类型不同,然后就开始怀疑这属于覆盖吗,到网上找到了答案,分析见接下来的网址: http://g ...

随机推荐

  1. 映射Map、队列Queue、优先级队列PriorityQueue

    映射Map 将对象映射到其他对象的能力是解决编程问题的有效方法.例如,考虑一个程序,它被用来检查 Java 的 Random 类的随机性.理想情况下, Random 会产生完美的数字分布,但为了测试这 ...

  2. vim conf文件配色

    VIM conf文件配色 一.配置文件 1.下载Nginx配置文件的语法文件:nginx.vim wget http://www.vim.org/scripts/download_script.php ...

  3. Maven使用--基本入门

    maven学习(上)- 基本入门用法 转载自:https://www.cnblogs.com/yjmyzz/p/3495762.html 参考: http://www.cnblogs.com/dave ...

  4. 【C语言】

    第3章 最简单的C程序设计 顺序程序设计 数据的表现形式及其运算 常量.变量.常变量.标识符 数据类型 整型.浮点型 整型数据的分类 最基本的整型类型 基本整型(int型):占2个或4个字节 短整型( ...

  5. go defer关键字使用规则

    defer 用于延迟函数的调用,每次defer都会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行 数据结构 type _defer struct { sp uintptr //函数栈指针 pc ...

  6. DNS重新绑定攻击

    来自微信外挂的安全风险 DNS重新绑定攻击 DDNS 动态域名设置

  7. zabbix告警推送至个人微信

    文章原文 自从接触zabbix后,就一直想着怎么才能把告警推送到个人微信上.有这样的想法主要是个人微信的使用频率远远要比钉钉,企业微信,邮箱,飞书等使用频率要高.比如我,就遇到过在周末的时候,因为没有 ...

  8. Python网络爬虫——京东商城商品列表

    Python_网络爬虫--京东商城商品列表 最近在拓展自己知识面,想学习一下其他的编程语言,处于多方的考虑最终选择了Python,Python从发布之初就以庞大的用户集群占据了编程的一席之地,pyth ...

  9. [考试总结]noip模拟40

    最近真的是爆炸啊... 到现在还是有不少没改出来.... 所以先写一下 \(T1\) 的题解.... 送花 我们移动右端点,之后我们用线段树维护全局最大值. 之后还要记录上次的位置和上上次的位置. 之 ...

  10. QT之ARM平台的移植

      在开发板中运行QT程序的基本条件是具备QT环境,那么QT的移植尤为重要,接下载我将和小伙伴们一起学习QT的移植. 一.准备材料 tslib源码 qt-everywhere-src-5.12.9.t ...