java统一返回标准类型
一、前言、背景
在如今前后端分离的时代,后端已经由传统的返回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(),"");
}
调用 参考SpringBoot
的HttpStatus
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统一返回标准类型的更多相关文章
- 使用Java泛型返回动态类型
返回一个指定类型的集合,并且clazz必须继承IGeoLog对象或者是其本身 <T extends IGeoLog> List<T> getLogListSql(Class&l ...
- springboot之全局处理统一返回
springboot之全局处理统一返回 简介 在REST风格的开发中,避免通常会告知前台返回是否成功以及状态码等信息.这里我们通常返回的时候做一次util的包装处理工作,如:Result类似的类,里面 ...
- 阿里官方Java代码规范标准《阿里巴巴Java开发手册 终极版 v1.3.0》
终极版 v1.3.0 2017年开春之际,阿里诚意献上重磅大礼:<阿里巴巴Java开发手册>,首次公开阿里官方Java代码规范标准.这套Java统一规范标准将有助于提高行业编码规范化水平, ...
- 阿里官方Java代码规范标准《阿里巴巴Java开发手册》下载
https://bbs.aliyun.com/read/306592.html?page=e 2017年开春之际,诚意献上重磅大礼:阿里巴巴Java开发手册,首次公开阿里官方Java代码规范标准. 这 ...
- JDBC数据类型、Java数据类型、标准sql类型
本概述是从<JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference>这本书中摘引来的.JavaSoft ...
- Java协变返回类型
今天看到句话:“支持重写方法时返回协变类型”. 那么什么事协变类型?在网上找了找资料,大体上明白了. Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方 ...
- java.lang.IllegalArgumentException异常 返回值类型的问题
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return usi ...
- Java 同时返回多个不同类型的方法
Java 同时返回多个不同类型的方法 2016年12月02日 16:05:07 FXBStudy 阅读数:10045 前言:虽然对于这种需求不常用,且比较冷门,但是还是有其存在的价值,再次做一下整 ...
- JAVA是否允许返回值类型不同的重载overload或覆盖override
在看<Thinking in java>的时候,看到子类的方法和父类的方法名字相同,但是返回值类型不同,然后就开始怀疑这属于覆盖吗,到网上找到了答案,分析见接下来的网址: http://g ...
随机推荐
- 【spring】69道Spring面试题和答案
原文地址:http://ifeve.com/spring-interview-questions-and-answers/ 目录 Spring 概述 依赖注入 Spring beans Spring注 ...
- Quartz任务调度(6)schedulerListener分版本超详细解析
schedulerListener 在我们的监听器实现类中,这个类中需实现的方法很多,不需要的可以给出空实现,下面是一些常用的用法: 方法 说明 jobScheduled() Scheduler 在有 ...
- Quartz任务调度(3)存储与持久化操作配置详细解
内存存储RAMJobStore Quartz默认使用RAMJobStore,它的优点是速度.因为所有的 Scheduler 信息都保存在计算机内存中,访问这些数据随着电脑而变快.而无须访问数据库或IO ...
- linux下静态库的制作
在我们编写软件的过程当中,少不了需要使用别人的库函数.因为大家知道,软件是一个协作的工程.作为个人来讲,你不可能一个人完成所有的工作.另外,网络上一些优秀的开源库已经被业内广泛接受,我们也没有必要把 ...
- vsftpd - FTP 服务器安装
由于要将本地程序上传至云服务器中,所以需要给云服务器端安装ftp服务器.记录一下ftp的安装过程,以便以后使用.服务器端所用系统为Ubuntu16.04. 1. 安装ftp服务器, apt-get i ...
- SpringBoot配置Cors跨域请求
一.同源策略简介 同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 什么是源 源[or ...
- 三 MongoDB进阶
1 Limit方法 概念:查询指定数量的数据,该方法接受一个数字参数作为查询记录数的数量 举个例子:查询集合col中最多2条记录数 2 Skip方法 概念:查询到的结果集中,跳过指定数量的数据,该方法 ...
- redis rpoplpush列表转移元素
文档出处:redisdoc.com/list/rpoplpush.html模式: 安全的队列 Redis的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message).一个客户 ...
- Golang slice作为函数参数
slice底层其实是一个结构体,len.cap.array分别表示长度.容量.底层数组的地址,当slice作为函数的参数传递的时候,跟普通结构体的传递是没有区别的:如果直接传slice,实参slice ...
- ES6 promise的应用
html部分 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <me ...