一、前言、背景

在如今前后端分离的时代,后端已经由传统的返回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. mfc HackerTools拖动文件

    VOID DragAcceptFiles(          HWND hWnd,    BOOL fAccept); 这个函数的调用,表示你要让某个窗体能够接受文件的拖入.第一个参数指定是哪个窗口, ...

  2. FileUtils常用方法 - commons-io常用工具类

    FileUtils常用常量 public static final long ONE_KB = 1024; public static final BigInteger ONE_KB_BI = Big ...

  3. 微信小程序学习笔记四 自定义组件

    1. 自定义组件 类似Vue或react中的自定义组件 小程序允许我们使用自定义组件的方式来构建页面 1.1 创建自定义组件 类似于页面, 一个自定义组件由json wxml wxss js 4个文件 ...

  4. Web应用安全防护-WAF

    web应用开发中不可避免需要考虑web应用的安全问题,那么常见的安全风险包含哪些呢? Web应用常见的安全风险 在web应用开发中可能存在以下的安全风险: 安全风险Top 10 A1:2017-注入 ...

  5. MediaWiki 语法简介

    本文尚在完善中... 图片 图片官方教程 图文并茂的内容读起来总是更加舒服,让我们在wiki里引入图片. 内部图片 上传图片 点击右侧上传文件,上传文件后会获得文件名 编辑图片 文件上传后在编辑框,如 ...

  6. ES6扩展——箭头函数

    1.箭头函数 在es6中,单一参数的单行箭头函数语法结构可以总结如下: const 函数名 = 传入的参数 => 函数返回的内容,因此针对于 const pop = arr => arr. ...

  7. Java通过网络图片之地址,下载到服务器

    @RequestMapping("/downloadTableQrcode") public String downloadTableQrcode(HttpServletReque ...

  8. Qt5完美解决 界面显示中文乱码

    最近在学习Qt,可是一直头疼于中文乱码问题,上网搜了一下,很多都是Qt4中使用如下方法: QTextCodec *codec = QTextCodec::codecForName("gbk& ...

  9. SSH无法正常连接服务器

    远程权限没有打开 #允许root登录 PermitRootLogin yes #不允许空密码登录 PermitEmptyPasswords no 远端的ssh信息有变化,本地保存的那个需要删掉 Use ...

  10. 2021-06-14 BZOJ4919:大根堆

    BZOJ4919:大根堆 Description: 题目描述   给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你 ...