<properties>
<springfox-swagger.version>2.9.2springfox-swagger.version>
properties>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>${springfox-swagger.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>${springfox-swagger.version}version>
dependency>
- 自定义公共Response异常信息
- 自定义公共Request信息: token
@Slf4j
@Configuration
@Profile({Const.Env.ENV_DEV, Const.Env.ENV_TEST})// 设置 dev test 环境开启
@EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerConfig {
@Autowired(required = false) //表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错
private SwaggerProperties swaggerProperties;
@Bean
public Docket createRestApi() {
//自定义Response异常信息
List<ResponseMessage> responseMessageList = new ArrayList<ResponseMessage>() { {
add(new ResponseMessageBuilder().code(ResultEnum.SUCCESS.getCode())
.message(ResultEnum.SUCCESS.getMessage()).build());
add(new ResponseMessageBuilder().code(ResultEnum.PARAM_ERROR.getCode())
.message(ResultEnum.PARAM_ERROR.getMessage()).responseModel(new ModelRef("ApiError")).build());
add(new ResponseMessageBuilder().code(ResultEnum.AUTHOR_EXPIRED.getCode())
.message(ResultEnum.AUTHOR_EXPIRED.getMessage()).build());
add(new ResponseMessageBuilder().code(ResultEnum.NO_PERMITION.getCode())
.message(ResultEnum.NO_PERMITION.getMessage()).build());
add(new ResponseMessageBuilder().code(ResultEnum.BUSSINESS_EXCEPTION.getCode())
.message(ResultEnum.BUSSINESS_EXCEPTION.getMessage()).build());
add(new ResponseMessageBuilder().code(ResultEnum.INTERNAL_SERVER_ERROR.getCode())
.message(ResultEnum.INTERNAL_SERVER_ERROR.getMessage()).build());
}
};
Parameter parameter = new ParameterBuilder().name(SecurityConst.TOKEN).description("head或者query带上token")
// -1是为了当一群都是默认值SWAGGER_PLUGIN_ORDER, TOKEN可以排在最前
.modelRef(new ModelRef("string")).parameterType("header").order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 1).required(true).build();
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()).select()
//扫描所有有注解的api,用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
.useDefaultResponseMessages(false)
//全局ResponseMessage
.globalResponseMessage(RequestMethod.GET, responseMessageList)
.globalResponseMessage(RequestMethod.POST, responseMessageList)
.globalResponseMessage(RequestMethod.PUT, responseMessageList)
.globalResponseMessage(RequestMethod.DELETE, responseMessageList)
//请求,带上token
.globalOperationParameters(Arrays.asList(parameter))
//ignoredParameterTypes
;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContactName(), "", swaggerProperties.getContactEmail()))
.version(swaggerProperties.getVersion())
.build();
}
}
/**
*
* 后台用户表 前端控制器
*
*
* @author wujie
* @since 2019-01-30
*/
@RestController
@RequestMapping(value = "/user", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Api(tags = "后台用户管理")
@Slf4j
public class AdminController {
@Autowired
private AdminService adminService;
@PostMapping("/login")
@ApiOperation(value = "用户登录", notes = "根据用户名和密码登录,返回token")
@ApiResponses({
@io.swagger.annotations.ApiResponse(code = 200, message = "登录成功"),
@io.swagger.annotations.ApiResponse(code = 4014, message = "用户不存在", response = ApiError.class),
@io.swagger.annotations.ApiResponse(code = 4018, message = "账号密码错误"),
@io.swagger.annotations.ApiResponse(code = 4015, message = "账号被冻结,请联系管理员")
})
public ApiResponse login(@ModelAttribute LoginParam param) {
//校验参数
BeanValidator.check(param);
String token = adminService.login(param);
HashMap map = Maps.newHashMap();
map.put("token", token);
return ApiResponse.success("登录成功", map);
}
}
/**
* Created by wujie on 2019/2/1.
* 用户登录表单参数
*/
@Data
@ApiModel(value = "LoginParam", description = "用户登录请求参数描述")
public class LoginParam {
@ApiModelProperty(value = "用户名(4-50个字符)", required = true, position = 1)
@NotEmpty(message = "用户名不能为空")
@Length(min = 4, max = 50, message = "用户名不能超过50个字符")
private String username;
@ApiModelProperty(value = "密码(不小于6个字符)", required = true, position = 2)
@NotEmpty(message = "密码不能为空")
@Length(min = 6, message = "密码不能小于6个字符")
private String password;
@ApiModelProperty(value = "是否自动登录", required = false, example = "false", position = 3)
private Boolean isAutoLogin = false;
}
在springfox.documentation.service.Operation发现原来parameters被按照字母进行了升序
this.parameters = FluentIterable.from(parameters)
.toSortedList(byParameterName());
private Comparator<Parameter> byParameterName() {
return new Comparator<Parameter>() {
@Override
public int compare(Parameter first, Parameter second) {
return first.getName().compareTo(second.getName());
}
};
}
主要是涉及:ExpandedParameterBuilderPlugin和ServiceModelToSwagger2Mapper的重现
/**
* Created by wujie on 2019/2/16.
* 自定义ExpandedParameterBuilderPlugin,主要是修正源码query传入请求参数postion无效
* 这里,将postion赋值给order
*/
@Primary
@Component
public class CustomSwaggerParameterBuilder implements ExpandedParameterBuilderPlugin {
private final DescriptionResolver descriptions;
private final EnumTypeDeterminer enumTypeDeterminer;
@Autowired
public CustomSwaggerParameterBuilder(
DescriptionResolver descriptions,
EnumTypeDeterminer enumTypeDeterminer) {
this.descriptions = descriptions;
this.enumTypeDeterminer = enumTypeDeterminer;
}
@Override
public void apply(ParameterExpansionContext context) {
Optional<ApiModelProperty> apiModelPropertyOptional = context.findAnnotation(ApiModelProperty.class);
if (apiModelPropertyOptional.isPresent()) {
fromApiModelProperty(context, apiModelPropertyOptional.get());
}
Optional<ApiParam> apiParamOptional = context.findAnnotation(ApiParam.class);
if (apiParamOptional.isPresent()) {
fromApiParam(context, apiParamOptional.get());
}
}
@Override
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
private void fromApiParam(ParameterExpansionContext context, ApiParam apiParam) {
String allowableProperty = emptyToNull(apiParam.allowableValues());
AllowableValues allowable = allowableValues(
fromNullable(allowableProperty),
context.getFieldType().getErasedType());
maybeSetParameterName(context, apiParam.name())
.description(descriptions.resolve(apiParam.value()))
.defaultValue(apiParam.defaultValue())
.required(apiParam.required())
.allowMultiple(apiParam.allowMultiple())
.allowableValues(allowable)
.parameterAccess(apiParam.access())
.hidden(apiParam.hidden())
.scalarExample(apiParam.example())
.complexExamples(examples(apiParam.examples()))
.order(SWAGGER_PLUGIN_ORDER)
.build();
}
private void fromApiModelProperty(ParameterExpansionContext context, ApiModelProperty apiModelProperty) {
String allowableProperty = emptyToNull(apiModelProperty.allowableValues());
AllowableValues allowable = allowableValues(
fromNullable(allowableProperty),
context.getFieldType().getErasedType());
maybeSetParameterName(context, apiModelProperty.name())
.description(descriptions.resolve(apiModelProperty.value()))
.required(apiModelProperty.required())
.allowableValues(allowable)
.parameterAccess(apiModelProperty.access())
.hidden(apiModelProperty.hidden())
.scalarExample(apiModelProperty.example())
.order(apiModelProperty.position()) //源码这里是: SWAGGER_PLUGIN_ORDER,需要修正
.build();
}
private ParameterBuilder maybeSetParameterName(ParameterExpansionContext context, String parameterName) {
if (!Strings.isNullOrEmpty(parameterName)) {
context.getParameterBuilder().name(parameterName);
}
return context.getParameterBuilder();
}
private AllowableValues allowableValues(final Optional<String> optionalAllowable, Class<?> fieldType) {
AllowableValues allowable = null;
if (enumTypeDeterminer.isEnum(fieldType)) {
allowable = new AllowableListValues(getEnumValues(fieldType), "LIST");
} else if (optionalAllowable.isPresent()) {
allowable = ApiModelProperties.allowableValueFromString(optionalAllowable.get());
}
return allowable;
}
private List<String> getEnumValues(final Class<?> subject) {
return transform(Arrays.asList(subject.getEnumConstants()), new Function<Object, String>() {
@Override
public String apply(final Object input) {
return input.toString();
}
});
}
}
/**
* Created by wujie on 2019/2/16.
* 重写 将Document转换成Swagger 类, 根据order进行排序
*/
@Primary //同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下
@Component("ServiceModelToSwagger2Mapper")
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class CustomModelToSwaggerMapper extends ServiceModelToSwagger2MapperImpl {
@Override
protected List<Parameter> parameterListToParameterList(List<springfox.documentation.service.Parameter> list) {
//list需要根据order|postion排序
list = list.stream().sorted((p1, p2) -> Integer.compare(p1.getOrder(), p2.getOrder())).collect(Collectors.toList());
// log.debug("************************************list:{}", list.toString());
return super.parameterListToParameterList(list);
}
}