文章目录
一、接口展示中的问题
现在大部分前后端的数据交互都是采用json格式,如我们经常用一个大的json包裹着数据发送的,但是在Swagger中,如果直接返回这个类对象,是展示不了data里面的数据的,更谈不上嵌套的json了,所以,为了让它能展示出data中的数据类型及格式,我们可以使用Java的泛型来做。
{
"code": 0,
"data": {},
"msg": "string"
}
二、BaseResult工具类
首先,我们要制定一个用于所有返回数据的最外层json框架的工具类,但是这个时候不能直接写这个类了,因为我们想在Swagger中显示内层数据的格式。Swagger是通过反射机制来展现类内部信息的,如果它只会返回一层数据的详细类型,即使类里面包含了其他类的对象,也不会再深入展示了,所以为了让它知道内部还有一个类对象要展示,那要传入这个对象的类型信息,所以要用到泛型。
package com.sc.springboot.utils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
//和以前唯一不一样的地方就是加了一个泛型T
@ApiModel("通用返回对象") //注释这个类的信息
public class BaseResult<T> implements Serializable {
//解释各字段的意思
@ApiModelProperty(value = "返回码", dataType = "String")
private int code;
@ApiModelProperty(value = "提示信息", dataType = "String")
private String msg;
@ApiModelProperty(value = "返回值", dataType = "String")
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
//几种构造方法
public BaseResult() {
}
public BaseResult(BaseResult.Type type, String msg) {
this.code = type.value;
this.msg = msg;
}
public BaseResult(BaseResult.Type type, String msg, T data) {
this.code = type.value;
this.msg = msg;
if (data != null) {
this.data = data;
}
}
//静态方法要使用泛型参数的话,要声明其为泛型方法
public static <T> BaseResult<T> success() {
return success("操作成功");
}
public static <T> BaseResult<T> success(T data) {
return success("操作成功", data);
}
public static <T> BaseResult<T> success(String msg) {
return success(msg, (T) null);
}
public static <T> BaseResult<T> success(String msg, T data) {
return new BaseResult<T>(BaseResult.Type.SUCCESS, msg, data);
}
public static <T> BaseResult<T> warn(String msg) {
return warn(msg, (T) null);
}
public static <T> BaseResult<T> warn(String msg, T data) {
return new BaseResult<T>(BaseResult.Type.WARN, msg, data);
}
public static <T> BaseResult<T> unAuth() {
return new BaseResult<T>(Type.UNAUTH, "未登陆", (T)null);
}
public static <T> BaseResult<T> error() {
return error("操作失败");
}
public static <T> BaseResult<T> error(String msg) {
return error(msg, (T)null);
}
public static <T> BaseResult<T> error(String msg, T data) {
return new BaseResult<T>(BaseResult.Type.ERROR, msg, data);
}
public static enum Type {
SUCCESS(200),
WARN(402),
UNAUTH(401),
ERROR(500);
private final int value;
private Type(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
}
这里编写的BaseResult类可以直接在工程中使用,和以前唯一的不同就是,在BaseResult返回值上带一个具体的data类型
三、使用BaseResult
1. 对应一个url该怎么返回数据
唯一的变化就是,在返回的BaseResult需要加上你要返回的泛型参数即可
@ApiOperation("获取登录用户信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "token", value = "token信息", paramType = "header")
})
@ApiResponses({
@ApiResponse(code=200,message = "请求成功"),
@ApiResponse(code=401,message = "未登陆"),
})
@GetMapping("getuserinfo")
public BaseResult<Supplier> getUserOfLogin(HttpServletRequest request) throws UnsupportedEncodingException {
//获取Headers中的参数
String token = request.getHeader("token");
//获取header,这是从Redis中获取登录信息
Supplier user = (Supplier) redisTemplate.opsForValue().get(token);
if(user != null){
return BaseResult.success(user);
}
return BaseResult.unAuth();
}
2. swagger中的数据展示
这样的返回信息,已经很棒了,但是有时候我们的json有会嵌套很多层,那么我们就需要嵌套多层泛型。
四、多层嵌套
1. 嵌入一层列表
比如,我们返回的不知一个用户信息了,想返回一个列表,可以直接用泛型表示列表就行了
@GetMapping("/getuserlist")
private BaseResult<List<Supplier> > getUser(){
List<Supplier> supplier = new LinkedList<>();
return BaseResult.success(supplier);
}
2. 返回分页信息
这种情况很常见,比如,我们要给数据分页,就得给出一个列表和一些页数信息,当前页,最大页等。
我们可以单独创建一个分页类
package com.lonelyzhe.sc.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("分页类型")
public class DivPage<T> {
@ApiModelProperty(value = "当前页数", dataType = "Integer")
private Integer current_page;
@ApiModelProperty(value = "最大页数", dataType = "Integer")
private Integer max_page;
@ApiModelProperty(value = "当前内容", dataType = "List")
private T content;
//省去了set、get方法,可以写上,或者用注解都行
}
返回的时候,填写DivPage的泛型参数就行了
@GetMapping("/getpagelist")
private BaseResult<DivPage<List<Supplier>> > getUser(){
List<Supplier> supplier = new LinkedList<>();
DivPage<List<Supplier>> divPage = new DivPage<>();
divPage.setCurrent_page(1);
divPage.setMax_page(20);
divPage.setContent(supplier);
return BaseResult.success(divPage);
}
3. 对象里有另外的对象
这种情况其实也挺多的,比如我们的用户有一个公司属性,但这个公司属性也是个对象,有公司id,公司名等,现在也要完整展示公司的信息,相当于嵌套里面有嵌套,其实和分页差不多,只是分页用的List本身就是泛型的,所以为了展示我们自己对象里的对象,需要把第一层对象设置为泛型。
(1)添加一个Company类
package com.lonelyzhe.sc.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "公司")
public class Company {
@ApiModelProperty(value = "公司id", dataType = "Integer")
private Integer id;
@ApiModelProperty(value = "公司名", dataType = "String")
private String name;
//省略get、set方法
}
(2)修改Supplier类,使其接收泛型参数
package com.lonelyzhe.jedisdemo.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "供应商信息")
public class Supplier<T>{ //这里多加一个泛型参数
@ApiModelProperty(value = "供应商id", dataType = "int")
private Integer supplier_id;
@ApiModelProperty(value = "供应商名称", dataType = "String")
private String supplier_name;
@ApiModelProperty(value = "一级分类", dataType = "String")
private String primary_supplier;
@ApiModelProperty(value = "二级分类", dataType = "String")
private String secondary_supplier;
@ApiModelProperty(value = "三级分类", dataType = "String")
private String tertiary_supplier;
@ApiModelProperty(value = "所属公司", dataType = "Company")
private Company company;
}
(3)返回结果
如果有很多层对象封装的话,那么每一层都需要泛型参数,如果一层中有多个封装的对象,那么可能要传入多个泛型参数。
五、总结
刚开始接触swagger有点懵,为啥返回不了里面的类的字段呀,后来查阅了很多资料,说得用泛型,又回想到Java编程思量里管理泛型和反射的章节,感觉swagger返回参数的时候应该是只读取了一层类型,如果类里面还包含其他的类对象,它就不知道具体类型是什么,此时需要用泛型去指定这个参数,让它知道类内部对象的类型才行。
当然,这只是最近研究的方法,如果有更好的方法就好,毕竟给每个类都加上泛型,还是麻烦的,增加了开发成本,不过相较于最后的自动Api结果,依然是真香!