一、前言、背景

在如今前后端分离的时代,后端已经由传统的返回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. 04.SpringMVC之用

    分析 Spring MVC 是怎么处理请求的.首先分析 HttpServletBean.FrameworkServlet 和 DispatcherServlet 这三个 Servlet 的处理过程,最 ...

  2. vue2.0中模拟数据的配置

    在开发过程中,有时候接口跟不上我们的进度,我们要测试,就需要自测. 现在vue已经升级到2.0版本了,早期在vue构建工程文件在build里面有dev-server.js,但是后来构建去除了该文件集成 ...

  3. Servlet学习之复习

    Servlet的注册与运行(Servlet程序通常需要存储在<web应用程序目录>\WEB-INF\classes\目录中) 1.注册Servlet:在web.xml文件中,一个<s ...

  4. python manage.py migrate出错

    python manage.py migrate出错 在建立Django项目过程中执行 python manage.py migrate命令,出现如下错误: 解决办法: 编辑D:\install fi ...

  5. QT学习日记篇-02-QT信号和槽

    课程大纲: <1>给控件改名字 随着UI界面的控件变多,如果使用系统自带的名称,后期会让人不明觉厉,说白了,就是掌握C++的命名规则:易懂,条例清晰,人性化 方法:直接点击控件,进入右侧对 ...

  6. 超详细kafka教程来啦

    Kafka的概念和入门 Kafka是一个消息系统.由LinkedIn于2011年设计开发. Kafka是一种分布式的,基于发布/订阅的消息系统.主要设计目标如下: 以时间复杂度O(1)的方式提供消息持 ...

  7. Python之telnetlib模块

    telnetlib是python标准库中的一员,我们可以使用该模块以telnet的方式与服务器交互.请观察下面示例了解它的用法: import telnetlib def run_telnet(hos ...

  8. Identity角色管理五(添加用户到角色组)

    因需要在用户列表中点详情按钮来到当前页,所以需要展示分组详情,并展示当前所属角色组的用户 public async Task<ActionResult> Details(string id ...

  9. python3.x内置函数

    函数 返回值类型 函数详情 abs(x) int|float 求绝对值,若是复数则返回复数的模 all(iterable) bool 若所有元素为真则返回True(非0,非空,非None) any(i ...

  10. Java日期时间API系列42-----一种高效的中文日期格式化和解析方法

    中文日期(2021年09月11日 和 二〇二一年九月十一日 )在生活中经常用到,2021年09月11日很好处理直接使用模板:yyyy年MM月dd日:二〇二一年九月十一日比较不好处理,需要每个数字进行转 ...