共计 6302 个字符,预计需要花费 16 分钟才能阅读完成。
为什么?
前后端拆散的时代,如果没有对立的返回格局,给前端的后果各式各样,预计前端的小伙伴就要骂娘了。
咱们想对自定义异样抛出指定的状态码排查谬误,对系统的不可预知的异样抛出敌对一点的异样信息。
咱们想让接口对立返回一些额定的数据,例如接口执行的工夫等等。
…
所以嘛,不论是日常和前端小伙伴对接,还是和其余部门进行接口对接,都应该返回固定的格局。
本文给出一个简略通用的返回格局,小伙伴们有需要,能够基于此版本依据本人的业务需要丰盛返回格局。
返回数据格式如下👇,有趣味的小伙伴们能够持续往下看 SpringBoot 是怎么来实现的。
{
"status": true,
"code": "0000",
"msg": "","data": {"id": 1,"deptId": 103,"userName":"admin","nickName":" 笑小枫 ","userType":"00","email":"xxf@163.com","phone":"15888888888","status":"0","remark":" 管理员 "}
}
怎么做?🧐
首先创立一个测试的 Controller,代码如下👇
package com.maple.demo.controller;
import com.maple.demo.util.ResultJson;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 笑小枫
* @date 2022/07/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/example")
public class TestResultController {@GetMapping("/testResult")
public Test testResult() {Test test = new Test();
test.setName("笑小枫");
test.setAge(18);
test.setRemark("大家好,我是笑小枫,喜爱我的小伙伴点个赞呗");
return test;
}
@GetMapping("/testResultJson")
public ResultJson testResultJson() {Test test = new Test();
test.setName("笑小枫");
test.setAge(18);
test.setRemark("大家好,我是笑小枫,喜爱我的小伙伴点个赞呗");
return new ResultJson(test);
}
@Data
static class Test {
private String name;
private Integer age;
private String remark;
}
}
咱们先看看这是调用返回的后果👀
{
"name": "笑小枫",
"age": 18,
"remark": "大家好,我是笑小枫,喜爱我的小伙伴点个赞"
}
而后在 util 包下定义一个对立的返回格局类,代码如下👇
package com.maple.demo.util;
import lombok.Data;
/**
* 对立返回信息包装类
*
* @author 笑小枫
* @date 2022/07/15
*/
@Data
public class ResultJson {
private static final String SUCCESS_CODE = "0000";
/**
* 成功失败的状态值,true:胜利;false:失败
* 这里返回编码为:“0000”,零碎就认为接口胜利;其余值,代表失败
*/
private Boolean status;
/**
* 状态码 正确为 0000
*/
private String code;
/**
* 返回提示信息
*/
private String msg;
/**
* 返回数据
*/
private Object data;
public ResultJson() {
this.status = true;
this.code = SUCCESS_CODE;
this.msg = "";
}
public ResultJson(Object data) {
this.status = true;
this.code = SUCCESS_CODE;
this.msg = "";
this.data = data;
}
public ResultJson(String code, String msg) {this.status = SUCCESS_CODE.equals(code);
this.code = code;
this.msg = msg;
}
/**
* 如果返回状态码非 0000,且接口状态为胜利,请应用这个
* @param status 接口申请状态
* @param code 返回 code 值
* @param msg 返回音讯
* @param data 返回数据
*/
public ResultJson(Boolean status, String code, String msg, Object data) {
this.status = status;
this.code = code;
this.msg = msg;
this.data = data;
}
}
一般版,代码侵入性强
这样咱们能够把后果对立放在 ResultJson 外面返回,代码如下👇
package com.maple.demo.controller;
import com.maple.demo.util.ResultJson;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 笑小枫
* @date 2022/07/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/example")
public class TestResultController {@GetMapping("/testResult")
public Test testResult() {Test test = new Test();
test.setName("笑小枫");
test.setAge(18);
test.setRemark("大家好,我是笑小枫,喜爱我的小伙伴点个赞呗");
return test;
}
/**
* 一般的返回
*/
@GetMapping("/testResultJson")
public ResultJson testResultJson() {Test test = new Test();
test.setName("笑小枫");
test.setAge(18);
test.setRemark("大家好,我是笑小枫,喜爱我的小伙伴点个赞呗");
return new ResultJson(test);
}
@Data
static class Test {
private String name;
private Integer age;
private String remark;
}
}
咱们看一下返回的后果👇
{
"status": true,
"code": "0000",
"msg": "","data": {"name":" 笑小枫 ","age": 18,"remark":" 大家好,我是笑小枫,喜爱我的小伙伴点个赞呗 "}
}
切面解决,代码无侵入
上述代码尽管实现了性能,但所有的返回后果都要解决,对代码有比拟强的侵入,Spring 领有各种切面的反对,让咱们看看如何代码无侵入的实现这个性能。
最初创立一个配置类,增加 @RestControllerAdvice
注解,代码如下👇
package com.maple.demo.config;
import com.alibaba.fastjson.JSON;
import com.maple.demo.util.ResultJson;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 对返回后果对立进行解决,包含返回后果格局对立包装,返回异样对立解决
*
* @author 笑小枫
* @date 2022/07/15
*/
@Slf4j
@RestControllerAdvice
public class RestResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(@NotNull MethodParameter returnType,
@NotNull Class<? extends HttpMessageConverter<?>> converterType) {return true;}
/**
* 返回后果包装对立返回格局
*
* @return 包装后的返回后果
*/
@Override
public Object beforeBodyWrite(Object body,
@NotNull MethodParameter returnType,
@NotNull MediaType selectedContentType,
@NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType,
@NotNull ServerHttpRequest request,
ServerHttpResponse response) {
// 指定返回的后果为 application/json 格局
// 不指定,String 类型转 json 后返回 Content-Type 是 text/plain;charset=UTF-8
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
ResultJson result = new ResultJson(body);
// 若返回类型是 ResultJson,则不进行批改
if (body == null) {if (returnType.getParameterType().isAssignableFrom(String.class)) {return JSON.toJSONString(result);
}
} else if (body instanceof ResultJson) {return body;} else if (body instanceof String) {return JSON.toJSONString(result);
}
return result;
}
}
这样就实现了对立后果的返回✌
咱们再申请文章最开始写的测试方法 http://127.0.0.1:6666/testResult
看一下返回的后果👀
{
"status": true,
"code": "0000",
"msg": "","data": {"name":" 笑小枫 ","age": 18,"remark":" 大家好,我是笑小枫,喜爱我的小伙伴点个赞呗 "}
}
这样对立返回格局就实现了,对代码没有的侵入,原来的代码该怎么写还是怎么写,是不是很 nice。
@RestControllerAdvice 介绍😴
首先理解一下 SpringBoot 的
@RestControllerAdvice
注解,它是 Spring 框架 3.2 新增的的注解
点进去这个注解源码,能够看到它是由@ControllerAdvice
和@ResponseBody
的组合注解
它通常用来定义@ExceptionHandler
,@InitBinder
以及@ModelAttribute
实用于所有办法@RequestMapping
的办法。
直白点说,这就是一个加强 Controller 的注解。次要实现以下三个方面的性能
- 全局异样解决
- 全局数据预处理
- 全局数据绑定
咱们看一下 @RestControllerAdvice
注解的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
@AliasFor(annotation = ControllerAdvice.class)
String[] value() default {};
@AliasFor(annotation = ControllerAdvice.class)
String[] basePackages() default {};
@AliasFor(annotation = ControllerAdvice.class)
Class<?>[] basePackageClasses() default {};
@AliasFor(annotation = ControllerAdvice.class)
Class<?>[] assignableTypes() default {};
@AliasFor(annotation = ControllerAdvice.class)
Class<? extends Annotation>[] annotations() default {};}
应用 @RestControllerAdvice
常做的两个性能的实现
- 返回对立格局的后果
- 异样对立解决
小结
好啦,本文就到这里了,咱们简略的总结一下,次要介绍了以下内容👇👇
- 为什么要返回对立的后果信息
- 手动封装对立的返回信息
- 应用 @RestControllerAdvice 主动封装返回信息
- 简略介绍 @RestControllerAdvice 注解
本文源码:https://github.com/hack-feng/maple-demo