swagger在线文档生成
1,添加依赖
pom.xml
<!--Swagger-UI API文档生产工具-->
<properties>
<swagger2.version>2.9.2</swagger2.version>
<swagger-models.version>1.6.0</swagger-models.version>
<swagger-annotations.version>1.6.0</swagger-annotations.version>
</properties>
<!--Swagger-UI API文档生产工具-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
<!--解决Swagger 2.9.2版本NumberFormatException-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger-models.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations.version}</version>
</dependency>
2,Swagger2Config
package com.macro.mall.config;
import com.macro.mall.common.config.BaseSwaggerConfig;
import com.macro.mall.common.domain.SwaggerProperties;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger API文档相关配置
* Created by macro on 2018/4/26.
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig extends BaseSwaggerConfig {
@Override
public SwaggerProperties swaggerProperties() {
return SwaggerProperties.builder()
.apiBasePackage("com.macro.mall.controller")
.title("mall后台系统")
.description("mall后台相关接口文档")
.contactName("macro")
.version("1.0")
.enableSecurity(true)
.build();
}
}
3,BaseSwaggerConfig
package com.example.mall1.api;
import org.springframework.context.annotation.Bean;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger基础配置
* Created by macro on 2020/7/16.
*/
public abstract class BaseSwaggerConfig {
@Bean
public Docket createRestApi() {
SwaggerProperties swaggerProperties = swaggerProperties();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(swaggerProperties))
.select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getApiBasePackage()))
.paths(PathSelectors.any())
.build();
if (swaggerProperties.isEnableSecurity()) {
docket.securitySchemes(securitySchemes()).securityContexts(securityContexts());
}
return docket;
}
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.contact(new Contact(swaggerProperties.getContactName(), swaggerProperties.getContactUrl(), swaggerProperties.getContactEmail()))
.version(swaggerProperties.getVersion())
.build();
}
private List<ApiKey> securitySchemes() {
//设置请求头信息
List<ApiKey> result = new ArrayList<>();
ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
result.add(apiKey);
return result;
}
private List<SecurityContext> securityContexts() {
//设置需要登录认证的路径
List<SecurityContext> result = new ArrayList<>();
result.add(getContextByPath("/*/.*"));
return result;
}
private SecurityContext getContextByPath(String pathRegex) {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(pathRegex))
.build();
}
private List<SecurityReference> defaultAuth() {
List<SecurityReference> result = new ArrayList<>();
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
result.add(new SecurityReference("Authorization", authorizationScopes));
return result;
}
/**
* 自定义Swagger配置
*/
public abstract SwaggerProperties swaggerProperties();
}
4,SwaggerProperties
package com.example.mall1.api;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* Swagger自定义配置
* Created by macro on 2020/7/16.
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
public class SwaggerProperties {
/**
* API文档生成基础路径
*/
private String apiBasePackage;
/**
* 是否要启用登录认证
*/
private boolean enableSecurity;
/**
* 文档标题
*/
private String title;
/**
* 文档描述
*/
private String description;
/**
* 文档版本
*/
private String version;
/**
* 文档联系人姓名
*/
private String contactName;
/**
* 文档联系人网址
*/
private String contactUrl;
/**
* 文档联系人邮箱
*/
private String contactEmail;
}
5,controller添加注解
package com.macro.mall.controller;
import com.macro.mall.common.api.CommonPage;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.model.SmsHomeBrand;
import com.macro.mall.service.SmsHomeBrandService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 首页品牌管理Controller
* Created by macro on 2018/11/6.
*/
@Controller
@Api(tags = "SmsHomeBrandController", description = "首页品牌管理")
@RequestMapping("/home/brand")
public class SmsHomeBrandController {
@Autowired
private SmsHomeBrandService homeBrandService;
@ApiOperation("添加首页推荐品牌")
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseBody
public CommonResult create(@RequestBody List<SmsHomeBrand> homeBrandList) {
int count = homeBrandService.create(homeBrandList);
if (count > 0) {
return CommonResult.success(count);
}
return CommonResult.failed();
}
@ApiOperation("修改品牌排序")
@RequestMapping(value = "/update/sort/{id}", method = RequestMethod.POST)
@ResponseBody
public CommonResult updateSort(@PathVariable Long id, Integer sort) {
int count = homeBrandService.updateSort(id, sort);
if (count > 0) {
return CommonResult.success(count);
}
return CommonResult.failed();
}
@ApiOperation("批量删除推荐品牌")
@RequestMapping(value = "/delete", method = RequestMethod.POST)
@ResponseBody
public CommonResult delete(@RequestParam("ids") List<Long> ids) {
int count = homeBrandService.delete(ids);
if (count > 0) {
return CommonResult.success(count);
}
return CommonResult.failed();
}
@ApiOperation("批量修改推荐状态")
@RequestMapping(value = "/update/recommendStatus", method = RequestMethod.POST)
@ResponseBody
public CommonResult updateRecommendStatus(@RequestParam("ids") List<Long> ids, @RequestParam Integer recommendStatus) {
int count = homeBrandService.updateRecommendStatus(ids, recommendStatus);
if (count > 0) {
return CommonResult.success(count);
}
return CommonResult.failed();
}
@ApiOperation("分页查询推荐品牌")
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<SmsHomeBrand>> list(@RequestParam(value = "brandName", required = false) String brandName,
@RequestParam(value = "recommendStatus", required = false) Integer recommendStatus,
@RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
List<SmsHomeBrand> homeBrandList = homeBrandService.list(brandName, recommendStatus, pageSize, pageNum);
return CommonResult.success(CommonPage.restPage(homeBrandList));
}
}
6,引入此类,修改mybatis Generator注释生成规则
package com.macro.mall;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
import java.util.Properties;
/**
* 自定义注释生成器
* Created by macro on 2018/4/26.
*/
public class CommentGenerator extends DefaultCommentGenerator {
private boolean addRemarkComments = false;
private static final String EXAMPLE_SUFFIX="Example";
private static final String MAPPER_SUFFIX="Mapper";
private static final String API_MODEL_PROPERTY_FULL_CLASS_NAME="io.swagger.annotations.ApiModelProperty";
/**
* 设置用户配置的参数
*/
@Override
public void addConfigurationProperties(Properties properties) {
super.addConfigurationProperties(properties);
this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments"));
}
/**
* 给字段添加注释
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
String remarks = introspectedColumn.getRemarks();
//根据参数和备注信息判断是否添加备注信息
if(addRemarkComments&&StringUtility.stringHasValue(remarks)){
// addFieldJavaDoc(field, remarks);
//数据库中特殊字符需要转义
if(remarks.contains("\"")){
remarks = remarks.replace("\"","'");
}
//给model的字段添加swagger注解
field.addJavaDocLine("@ApiModelProperty(value = \""+remarks+"\")");
}
}
/**
* 给model的字段添加注释
*/
private void addFieldJavaDoc(Field field, String remarks) {
//文档注释开始
field.addJavaDocLine("/**");
//获取数据库字段的备注信息
String[] remarkLines = remarks.split(System.getProperty("line.separator"));
for(String remarkLine:remarkLines){
field.addJavaDocLine(" * "+remarkLine);
}
addJavadocTag(field, false);
field.addJavaDocLine(" */");
}
@Override
public void addJavaFileComment(CompilationUnit compilationUnit) {
super.addJavaFileComment(compilationUnit);
//只在model中添加swagger注解类的导入
if(!compilationUnit.getType().getFullyQualifiedName().contains(MAPPER_SUFFIX)&&!compilationUnit.getType().getFullyQualifiedName().contains(EXAMPLE_SUFFIX)){
compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME));
}
}
}
7,实体类属性,使用@ApiModelProperty注解
(1)直接以controller的传参
(2)dto的注解方式传参。swagger
package com.macro.mall.dto;
import com.macro.mall.validator.FlagValidator;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
/**
* 品牌传递参数
* Created by macro on 2018/4/26.
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class PmsBrandParam {
@NotEmpty
@ApiModelProperty(value = "品牌名称",required = true)
private String name;
@ApiModelProperty(value = "品牌首字母")
private String firstLetter;
@Min(value = 0)
@ApiModelProperty(value = "排序字段")
private Integer sort;
@FlagValidator(value = {"0","1"}, message = "厂家状态不正确")
@ApiModelProperty(value = "是否为厂家制造商")
private Integer factoryStatus;
@FlagValidator(value = {"0","1"}, message = "显示状态不正确")
@ApiModelProperty(value = "是否进行显示")
private Integer showStatus;
@NotEmpty
@ApiModelProperty(value = "品牌logo",required = true)
private String logo;
@ApiModelProperty(value = "品牌大图")
private String bigPic;
@ApiModelProperty(value = "品牌故事")
private String brandStory;
}
###用户验证状态是否在指定范围内的注解
FlagValidator
package com.macro.mall.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 用户验证状态是否在指定范围内的注解
* Created by macro on 2018/4/26.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Constraint(validatedBy = FlagValidatorClass.class)
public @interface FlagValidator {
String[] value() default {};
String message() default "flag is not found";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
FlagValidatorClass
package com.macro.mall.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 状态标记校验器
* Created by macro on 2018/4/26.
*/
public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Integer> {
private String[] values;
@Override
public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.value();
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
boolean isValid = false;
if(value==null){
//当状态为空时使用默认值
return true;
}
for(int i=0;i<values.length;i++){
if(values[i].equals(String.valueOf(value))){
isValid = true;
break;
}
}
return isValid;
}
}