Swagger2解决通用返回结果是泛型的问题:swagger2.9.2+ swagger-bootstrap-ui-1.8.5
依赖关系
<!-- Swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-swagger2}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-swagger2}</version>
</dependency>
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger-bootstrap-ui}</version>
</dependency>
通用的返回结果类:主要是要解决data属性的参照关系。
@ApiModel(description = "通用响应返回对象")
public class JsonResult<T> extends BaseResult {
protected static Logger logger = LoggerFactory.getLogger(JsonResult.class);
/**
* 返回结果代码
*/
@ApiModelProperty(value = "结果代码", position = 0)
private int code;
/**
* 返回结果类型
*/
@ApiModelProperty(value = "结果类型", position = 1)
private String type;
/**
* 具体的错误信息
*/
@ApiModelProperty(value = "错误信息", position = 2)
private String message;
/**
* Exception类
*/
@ApiModelProperty(value = "异常类", position = 3)
private String exception;
/**
* 返回结果数据
*/
@ApiModelProperty(value = "结果数据", position = 4 )
private T data;
/**
* 是否成功,0表示成功,其他都是失败
*/
@ApiModelProperty(value = "是否成功", position = 5, example = "true")
private boolean success = true;
/**
* 具体的异常类 <br>
* JSON序列化时,将该字段忽略
*/
@JSONField(serialize = false)
@JsonIgnore
@ApiModelProperty(value = "具体的异常类", position = 6)
private Exception realException;
....
....
}
我用了最简单的方法,重写了该类:
com.github.xiaoymin.swaggerbootstrapui.web.SwaggerBootstrapUiController
我的类:
package cn.boot4j.core.support.swagger;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
import static springfox.documentation.swagger.common.HostNameProvider.componentsFrom;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.util.UriComponents;
import com.github.xiaoymin.swaggerbootstrapui.model.SwaggerBootstrapUiPathInstance;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiSort;
import io.swagger.models.Model;
import io.swagger.models.Swagger;
import io.swagger.models.SwaggerBootstrapUi;
import io.swagger.models.SwaggerBootstrapUiPath;
import io.swagger.models.SwaggerBootstrapUiTag;
import io.swagger.models.SwaggerExt;
import io.swagger.models.properties.Property;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.service.Documentation;
import springfox.documentation.service.Tag;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
@Controller
@ApiIgnore
public class SwaggerUiController {
/***
* sort排序接口
*/
public static final String DEFAULT_SORT_URL = "/v2/api-docs-ext";
private static final String HAL_MEDIA_TYPE = "application/hal+json";
private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerUiController.class);
private final ServiceModelToSwagger2Mapper mapper;
private final DocumentationCache documentationCache;
private final JsonSerializer jsonSerializer;
private final String hostNameOverride;
@Autowired
public SwaggerUiController(Environment environment, ServiceModelToSwagger2Mapper mapper,
DocumentationCache documentationCache, JsonSerializer jsonSerializer) {
this.mapper = mapper;
this.documentationCache = documentationCache;
this.jsonSerializer = jsonSerializer;
this.hostNameOverride = environment.getProperty("springfox.documentation.swagger.v2.host", "DEFAULT");
;
}
@RequestMapping(value = DEFAULT_SORT_URL, method = RequestMethod.GET, produces = { APPLICATION_JSON_VALUE,
HAL_MEDIA_TYPE })
@ResponseBody
public ResponseEntity<Json> apiSorts(@RequestParam(value = "group", required = false) String swaggerGroup,
HttpServletRequest request) {
String groupName = Optional.fromNullable(swaggerGroup).or(Docket.DEFAULT_GROUP_NAME);
Documentation documentation = documentationCache.documentationByGroup(groupName);
if (documentation == null) {
LOGGER.warn("Unable to find specification for grouRp {}", groupName);
return new ResponseEntity<Json>(HttpStatus.NOT_FOUND);
}
Swagger swagger = mapper.mapDocumentation(documentation);
UriComponents uriComponents = componentsFrom(request, swagger.getBasePath());
swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
if (isNullOrEmpty(swagger.getHost())) {
swagger.host(hostName(uriComponents));
}
// 扩展
swagger = extend(swagger);
SwaggerExt swaggerExt = new SwaggerExt(swagger);
// swaggerBootstrapUi.setTagSortLists(getSortTag(request,documentation));
swaggerExt.setSwaggerBootstrapUi(initSwaggerBootstrapUi(request, documentation));
// Method 层排序
return new ResponseEntity<Json>(jsonSerializer.toJson(swaggerExt), HttpStatus.OK);
}
@SuppressWarnings("deprecation")
private SwaggerBootstrapUi initSwaggerBootstrapUi(HttpServletRequest request, Documentation documentation) {
SwaggerBootstrapUi swaggerBootstrapUi = new SwaggerBootstrapUi();
WebApplicationContext wc = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
Iterator<Tag> tags = documentation.getTags().iterator();
List<SwaggerBootstrapUiTag> targetTagLists = Lists.newArrayList();
// Ctl层排序
Map<String, Object> beansWithAnnotation = wc.getBeansWithAnnotation(Controller.class);
// path排序
List<SwaggerBootstrapUiPath> targetPathLists = Lists.newArrayList();
while (tags.hasNext()) {
Tag sourceTag = tags.next();
String tagName = sourceTag.getName();
boolean exists = false;
Class<?> aClass = null;
Api api = null;
for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
aClass = entry.getValue().getClass();
api = aClass.getAnnotation(Api.class);
if (api != null) {
// 是否相等
if (Lists.newArrayList(api.tags()).contains(tagName)) {
exists = true;
break;
}
}
}
// 获取order值
int order = Integer.MAX_VALUE;
SwaggerBootstrapUiTag tag = new SwaggerBootstrapUiTag(order);
tag.name(sourceTag.getName()).description(sourceTag.getDescription());
if (exists) {
// 优先获取api注解的position属性,如果不等于0,则取此值,否则获取apiSort注解,判断是否为空,如果不为空,则获取apisort的值,优先级:@Api-position>@ApiSort-value
int post = api.position();
if (post == 0) {
ApiSort annotation = aClass.getAnnotation(ApiSort.class);
if (annotation != null) {
order = annotation.value();
}
} else {
order = post;
}
// targetTagLists.add(new
// Tag(sourceTag.getName(),sourceTag.getDescription(),order,sourceTag.getVendorExtensions()));
tag.setOrder(order);
// 获取父级path
String parentPath = "";
RequestMapping parent = aClass.getAnnotation(RequestMapping.class);
if (parent != null) {
parentPath = parent.value()[0];
}
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
List<SwaggerBootstrapUiPath> paths = new SwaggerBootstrapUiPathInstance(parentPath, method).match();
if (paths != null && paths.size() > 0) {
targetPathLists.addAll(paths);
}
}
}
targetTagLists.add(tag);
}
Collections.sort(targetTagLists, new Comparator<SwaggerBootstrapUiTag>() {
@Override
public int compare(SwaggerBootstrapUiTag o1, SwaggerBootstrapUiTag o2) {
return o1.getOrder().compareTo(o2.getOrder());
}
});
Collections.sort(targetPathLists, new Comparator<SwaggerBootstrapUiPath>() {
@Override
public int compare(SwaggerBootstrapUiPath o1, SwaggerBootstrapUiPath o2) {
return o1.getOrder().compareTo(o2.getOrder());
}
});
swaggerBootstrapUi.setTagSortLists(targetTagLists);
swaggerBootstrapUi.setPathSortLists(targetPathLists);
return swaggerBootstrapUi;
}
private String hostName(UriComponents uriComponents) {
if ("DEFAULT".equals(hostNameOverride)) {
String host = uriComponents.getHost();
int port = uriComponents.getPort();
if (port > -1) {
return String.format("%s:%d", host, port);
}
return host;
}
return hostNameOverride;
}
private Swagger extend(Swagger swagger) {
// 响应返回参数增强
Iterator<Map.Entry<String, Model>> it = swagger.getDefinitions().entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Model> entry = it.next();
Model model = entry.getValue();
String key = entry.getKey();
if (key.contains("JsonResult")) {
Map<String, Property> props = model.getProperties();
Property dataProp = props.get("data");
Property newProp = SwaggerUtil.getNewProp(dataProp, SwaggerUtil.getRealType(key), swagger.getDefinitions());
props.put("data", newProp);
}
}
return swagger;
}
}
关键代码只有1行:
// >> 扩展~~~~~~~
swagger = extend(swagger);
// >> end
运行效果:
ArrayRefProperty:
package cn.boot4j.core.support.swagger;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.RefProperty;
import io.swagger.models.refs.GenericRef;
import io.swagger.models.refs.RefType;
/**
* 同时拥有ArrayProperty和RefProperty的特性
* @author ChenZhiPing 2018年10月30日 下午6:08:57
*/
public class ArrayRefProperty extends ArrayProperty {
private GenericRef genericRef;
public String get$ref() {
return genericRef.getRef();
}
public void set$ref(String ref) {
this.genericRef = new GenericRef(RefType.DEFINITION, ref);
// $ref
RefProperty items = new RefProperty();
items.setType(ref);
items.set$ref(ref);
this.items(items);
}
}
注意Controller的写法:约定**你我约定**(具体的JsonResult泛型必须指定)
package cn.boot4j.product.demo.web.ui;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cn.boot4j.core.base.BaseController;
import cn.boot4j.core.support.db.DBResult;
import cn.boot4j.core.support.service.JsonResult;
import cn.boot4j.product.demo.model.customer.Customer;
import cn.boot4j.product.demo.model.customer.CustomerDBParam;
import cn.boot4j.product.demo.model.operator.Operator;
import cn.boot4j.product.demo.model.operator.OperatorType;
import cn.boot4j.product.demo.service.customer.ICustomerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* @author ChenZhiPing 2017年9月26日 上午11:14:38
*/
@RestController
@RequestMapping("demo")
@Api(value = "DemoController", tags = { "10.JsonResult响应结果" }, hidden = true)
@SuppressWarnings("unchecked")
public class DemoController extends BaseController {
@Autowired
private ICustomerService customerService;
@ApiOperation(value = "JsonResult«List«T»»", notes = "List类型")
@RequestMapping(value = "list", method = RequestMethod.GET)
public JsonResult<List<Customer>> list() {
try {
Object data = customerService.findAll();
return success(data);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "JsonResult«Map«B, B»»", notes = "Map类型")
@RequestMapping(value = "mapOnly", method = RequestMethod.GET)
public JsonResult<Map<String, Integer>> mapOnly() {
try {
List<Customer> data = (List<Customer>) customerService.findAll();
Map<String, Integer> map = new HashMap<String, Integer>();
if (data.size() > 0) {
for (Customer c : data) {
map.put(c.getName(), c.getId());
}
}
return success(map);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "JsonResult«Map«B, T»»", notes = "Map类型")
@RequestMapping(value = "map", method = RequestMethod.GET)
public JsonResult<Map<String, Customer>> map() {
try {
List<Customer> data = (List<Customer>) customerService.findAll();
Map<String, Customer> map = new HashMap<String, Customer>();
if (data.size() > 0) {
for (Customer c : data) {
map.put(c.getName(), c);
}
}
return success(map);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "JsonResult«Set«T»»", notes = "Set类型")
@RequestMapping(value = "set", method = RequestMethod.GET)
public JsonResult<Set<Customer>> set() {
try {
List<Customer> data = (List<Customer>) customerService.findAll();
Set<Customer> set = new TreeSet<>();
if (data.size() > 0) {
for (Customer c : data) {
set.add(c);
}
}
return success(set);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "JsonResult«DBResult«T»»", notes = "DBResult类型")
@RequestMapping(value = "query", method = RequestMethod.GET)
public JsonResult<DBResult<Customer>> query() {
try {
Object data = customerService.query(new CustomerDBParam());
return success(data);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "JsonResult«B»", notes = "只有基础类型")
@RequestMapping(value = "deleteByPk", method = RequestMethod.GET)
public JsonResult<Boolean> deleteByPk() {
try {
Object data = customerService.deleteByPk(0);
return success(data);
} catch (Exception e) {
return exception(e);
}
}
@ApiOperation(value = "复杂T", notes = "复杂类型")
@RequestMapping(value = "complex", method = RequestMethod.GET)
public JsonResult<Map<Map<Long, Operator>, List<Map<String, Customer>>>> complex() {
try {
Map<Long, Operator> m1 = new HashMap<Long, Operator>();
Operator o = new Operator();
o.setOwnerIdentityId((long) 20087);
o.setDisplayName("很漂亮的操作员");
o.setLastUpdateDate(new Date());
o.setOperatorType(OperatorType.SP_OPERATOR);
o.setRemark("测试复杂的Swagger泛型展示");
m1.put(o.getOwnerIdentityId(), o);
Map<String, Customer> m2 = (Map<String, Customer>) this.map().getData();
List<Object> list = new ArrayList<Object>();
list.add(m2);
@SuppressWarnings("rawtypes")
Map map = new HashMap();
map.put(m1, list);
return success(map);
} catch (Exception e) {
return exception(e);
}
}
}
SwaggerUtil:
package cn.boot4j.core.support.swagger;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeanUtils;
import io.swagger.models.Model;
import io.swagger.models.properties.AbstractProperty;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.BooleanProperty;
import io.swagger.models.properties.DateTimeProperty;
import io.swagger.models.properties.IntegerProperty;
import io.swagger.models.properties.LongProperty;
import io.swagger.models.properties.ObjectProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.PropertyBuilder;
import io.swagger.models.properties.PropertyBuilder.PropertyId;
import io.swagger.models.properties.RefProperty;
import io.swagger.models.properties.StringProperty;
/**
* @author ChenZhiPing 2018年10月31日 下午1:44:50
*/
public class SwaggerUtil {
/**
* 判断是否Swagger基本类型
* @param type
* @return
*/
public static boolean isBaseType(String type) {
return SwaggerUtil.getSwaggerProperty(type) != null;
}
/**
* 获取Swagger支持的类型
* @return
*/
public static Map<String, AbstractProperty> getPropMap() {
Map<String, AbstractProperty> map = new HashMap<String, AbstractProperty>();
map.put("integer", new IntegerProperty());
map.put("int", new IntegerProperty());
map.put("long", new LongProperty());
map.put("string", new StringProperty());
map.put("object", new ObjectProperty());
map.put("array", new ArrayProperty());
map.put("boolean", new BooleanProperty());
map.put("date", new DateTimeProperty());
return map;
}
/**
* 通过java类型获取Swagger类型
* @param type javaType
* @return swaggerType
*/
public static AbstractProperty getSwaggerProperty(String type) {
type = type.toLowerCase();
return SwaggerUtil.getPropMap().get(type);
}
public static boolean isMap(String type) {
type = type.toLowerCase();
return type.startsWith("map");
}
public static boolean isIterable(String type) {
type = type.toLowerCase();
return type.startsWith("list") || type.startsWith("set");
}
/**
* 获取非基本类型的T<br>
* new String[] { "A<List<C1>>", "A<C2>", "A<B<String,<String,List<C4>>>>" }
* @param type
* @return C1,C2,C3,C4
*/
public static String getRef(String type) {
try {
String m = type.substring(type.lastIndexOf("«") + 1, type.indexOf("»"));
String[] cc = m.split(",");
for (String c : cc) {
if (!SwaggerUtil.isBaseType(c)) {
return c;
}
}
return type;
} catch (Exception e) {
}
return "!!Unknown T!!";
}
/**
* 获取对象类型,主要是剥离第一层<>
* @param type JsonResult<Map<Operator, List<Map<String, Customer>>>>
* @return Map<Operator, List<Map<String, Customer>>>
*/
public static String getRealType(String type) {
try {
String m = type.substring(type.indexOf("«") + 1, type.lastIndexOf("»"));
return m;
} catch (Exception e) {
}
return type;
}
/**
* 判断是否存在非基本类型<参照类型>
* @param type
* @return
*/
public static boolean hasRef(String type) {
if (type.indexOf("»") > 0) {
try {
String m = type.substring(type.lastIndexOf("«") + 1, type.indexOf("»"));
String[] cc = m.split(",");
for (String c : cc) {
if (!SwaggerUtil.isBaseType(c)) {
return true;
}
}
return false;
} catch (Exception e) {
return false;
}
} else {
return !SwaggerUtil.isBaseType(type);
}
}
/**
* 递归处理泛型类型 <br>
* JsonResult<Map<Map<Long, Operator>, List<Map<String, Customer>>>>
* @param dataProp
* @param type
* @param definitions
* @return
*/
public static Property getNewProp(Property dataProp, String type, Map<String, Model> definitions) {
Property newProp = null;
Model model = definitions.get(type);
Map<String, Property> props = null;
if (null != model) {
props = model.getProperties();
}
if (null == props) {
props = new HashMap<String, Property>();
}
String realType = SwaggerUtil.getRealType(type);
if (SwaggerUtil.isMap(type)) {
String[] realTypes = SwaggerUtil.splitByComma(realType);
Map<PropertyId, Object> argsK = new HashMap<PropertyId, Object>();
argsK.put(PropertyBuilder.PropertyId.DESCRIPTION, "Map的键");
argsK.put(PropertyBuilder.PropertyId.TYPE, realTypes[0].toLowerCase());
AbstractProperty _prop0 = SwaggerUtil.getSwaggerProperty(realTypes[0]);
Property propK = PropertyBuilder.build(null == _prop0 ? "object" : _prop0.getType(),
null == _prop0 ? null : _prop0.getFormat(), argsK);
propK.setName("key");
Map<PropertyId, Object> argsV = new HashMap<PropertyId, Object>();
argsV.put(PropertyBuilder.PropertyId.DESCRIPTION, "Map的值");
argsV.put(PropertyBuilder.PropertyId.TYPE, realTypes[1].toLowerCase());
AbstractProperty _prop1 = SwaggerUtil.getSwaggerProperty(realTypes[1]);
Property propV = PropertyBuilder.build(null == _prop1 ? "object" : _prop1.getType(),
null == _prop1 ? null : _prop1.getFormat(), argsV);
propV.setName("value");
if (!realType.equals(type)) {
propK = SwaggerUtil.getNewProp(propK, realTypes[0], definitions);
propV = SwaggerUtil.getNewProp(propV, realTypes[1], definitions);
}
props.put(propK.getName(), propK);
props.put(propV.getName(), propV);
newProp = new RefProperty();
BeanUtils.copyProperties(dataProp, newProp);
((RefProperty) newProp).set$ref(type);
} else if (SwaggerUtil.isIterable(type)) {
String ref = SwaggerUtil.getRealType(type);
newProp = new ArrayRefProperty();
BeanUtils.copyProperties(dataProp, newProp);
((ArrayRefProperty) newProp).set$ref(ref);
((ArrayRefProperty) newProp).setType(ArrayRefProperty.TYPE);
if (!realType.equals(type)) {
SwaggerUtil.getNewProp(dataProp, realType, definitions);
}
} else if (SwaggerUtil.isBaseType(type)) {
Map<PropertyId, Object> args = new HashMap<PropertyId, Object>();
args.put(PropertyBuilder.PropertyId.DESCRIPTION, dataProp.getDescription());
args.put(PropertyBuilder.PropertyId.TYPE, type.toLowerCase());
AbstractProperty _prop = SwaggerUtil.getSwaggerProperty(type);
newProp = PropertyBuilder.build(_prop.getType(), _prop.getFormat(), args);
newProp.setName(dataProp.getName());
} else if (SwaggerUtil.hasRef(type)) {
newProp = new RefProperty();
BeanUtils.copyProperties(dataProp, newProp);
((RefProperty) newProp).set$ref(type);
} else {
}
if (null != model) {
model.setProperties(props);
}
return newProp;
}
public static String[] splitByComma(String str) {
int index = 0;
int has = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if ("«".equals(c + "")) {
has++;
}
if ("»".equals(c + "")) {
has--;
}
if (",".equals(c + "") && has == 0) {
index = i;
}
}
String[] arr = new String[2];
arr[0] = str.substring(0, index);
arr[1] = str.substring(index + 1);
return arr;
}
public static void main(String[] args) {
String[] ss = new String[] { "A«List«C1»»", "A«C2»", "A«B«String,«String,List«C4»»»»" };
for (String s : ss) {
String c = SwaggerUtil.getRealType(s);
System.out.println(c);
}
String[] s2 = new String[] { "A,B«List«C1»»", "Map«A,B»,C«List«D»»",
"Map«Map«A,B»,C«List«D»»,Map«A,B»,C«List«D»»»,C«List«D»»" };
for (String s : s2) {
String[] arr = SwaggerUtil.splitByComma(s);
System.out.println(arr[0]);
System.out.println(arr[1]);
}
}
}
最复杂的情况:JsonResult<Map<Map<Long, Operator>, List<Map<String, Customer>>>>
响应示例:
{
"code": 0,
"type": "",
"message": "",
"exception": "",
"data": {
"value": [
{
"value": {
"id": 0,
"addr": "",
"age": 0,
"name": "",
"nickName": "",
"password": "",
"registorTime": "",
"sex": ""
},
"key": ""
}
],
"key": {
"value": {
"displayName": "",
"lastUpdateDate": "",
"lastUpdateUser": "",
"loginPassword": "",
"operatorName": "",
"operatorType": "",
"ownerIdentityId": 0,
"ownerIdentityName": "",
"ownerIdentityType": "",
"remark": "",
"unionid": ""
},
"key": 0
}
},
"success": true
}
package cn.boot4j.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import cn.boot4j.core.base.BaseSwagger;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* <h2>为什么要用Swagger</h2> RESTful
* API就有可能要面对多个开发人员或多个开发团队:IOS开发、Android开发或是Web开发等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful
* API文档来记录所有接口细节,然而这样的做法有以下几个问题:
* <ul>
* <li>由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。</li>
* <li>随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。</li>
* </ul>
* <h2>添加Swagger2依赖</h2>
*
* <pre class="code">
* {@code
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
}
* </pre>
*
* <h2>Swagger2配置方法,主要是用到Controller类上</h2>
* <ul>
* <li>通过@ApiOperation注解来给API增加说明</li>
* <li>通过@ApiImplicitParams、@ApiImplicitParam注解来给参数增加说明</li>
* <li>通过@EnableSwaggerBootstrapUI来启用Swagger相关的特殊配置,boot4j项目已经默认启用,见@SwaggerUiController
* </ul>
* <h2>启动SpringBoot程序,访问如下链接:</h2> {@link http://localhost:8080/swagger-ui.html}
* @author ChenZhiPing 2017年10月7日 下午9:38:19
*/
@Configuration
@EnableSwagger2
// @EnableSwaggerBootstrapUI
@Order(Ordered.HIGHEST_PRECEDENCE + 1000)
public class SwaggerConfiguration extends BaseSwagger {
/**
* 在Swagger2增加自动认证功能,注意,认证时必须带上“Bearer 2ece95f5-daf1-42e5-b866-4e8f2d454199”
* <code>这里是个坑:必须带上“Bearer空格token” 格式,否认证失败!!!</code>
*/
@Bean
public Docket baseApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("系统基础支持").useDefaultResponseMessages(false)
.apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("cn.boot4j.core.support"))
.paths(PathSelectors.regex("^(?!auth).*$")).build().securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
/**
* 这个Bean不能增加,会导致id不能返回
* @return
* @Bean public ObjectMapper objectMapper() { return new
* ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); }
*/
}