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详解(十)加载配置文件
在项目中有些参数经常需要修改,或者后期可能会有改动时,那我们最好把这些参数放到properties文件中,在源代码中读取properties里面的配置,这样后期只需要改动properties文件即可, ...
- 【IDE】WebStorm常用快捷键
WebStorm常用快捷键 1. ctrl + shift + n: 打开工程中的文件,目的是打开当前工程下任意目录的文件. 2. ctrl + j: 输出模板 3. ctrl + b: 跳到变量申明 ...
- 初识cookie
package day01.cookies; import java.io.IOException; import java.net.URLDecoder; import java.net.URLEn ...
- 你知道 JavaScript 中的 Arguments 对象都有哪些用途吗?
JavaScript 中 Arguments 对象的用途总结. 前言 相信我们很多人在代码开发的过程中都使用到过一个特殊的对象 -- Arguments 对象. 在实际开发中,Arguments 对象 ...
- Dynamics CRM实体系列之1:N、N:1以及N:N关系
Dynamics CRM在实施过程中会遇到很多多个实体关联的问题,这样可以实现多个实体的记录通过关联的字段实现数据的综合展示,在Sql Server里面叫做外键,在Dynamics CRM叫做关系.D ...
- Learning ROS: Aboat URDF (Unified Robot Description Format)
Building a Visual Robot Model with URDF from Scratch roscore &# With $(find urdf_tutorial), this ...
- vsftpd 参数说明
2021-07-28 该文章为转载文章,非原创 参数作用# 是否允许匿名访问 [ 12行 ]anonymous_enable=[YES|NO]# 是否允许本地用户访问( /etc/passwd中的用户 ...
- 乐肴2.0环境改名后,需要删除原来的软链接(public/storage)
rm -rf public/storage php artisan storage:link
- 硕盟type-c转接头|四合一多功能扩展坞
硕盟SM-T54是一款 TYPE C转HDMI+VGA+USB3.0+PD3.0四合一多功能扩展坞,支持四口同时使用,您可以将含有USB 3.1协议的电脑主机,通过此产品连接到具有HDMI或VGA的显 ...
- MySQL数据库初体验
一.数据库的基本概念1.数据(Data) 描述事物的符号记录 包括数字,文字,图形,图像,声音,档案记录等 以"记录"形式按统一的格式进行存储 2.表 将不同的记录组织在一起 用来 ...