写在前面
本文将在第一篇《项目骨架搭建》的基础上整合Swagger-UI,实现可以在线阅读API文档这一功能。
Swagger-UI简介
Swagger-UI是HTML、CSS和Javascript的一个集合,可以动态地根据注解生成在线API文档,本篇将要整合的Swagger-UI版本为2系列。
Swagger-UI常用的一些注解如下所示:
(1)@Api
:用于修饰Controller类,可生成Controller相关的文档信息;
(2)@ApiOperation
:用于修饰Controller类中的方法,可生成接口方法相关的文档信息;
(3)@ApiParam
:用于修饰接口中方法的参数,可生成接口参数相关的文档信息;
(4)@ApiModelProperty
:用于修饰实体类的属性,当实体类是请求参数或返回结果时,会直接生成相关的文档信息。
关于Swagger-UI的详细介绍,可以参阅笔者其他的文章,此处不做过多介绍。
整合Swagger-UI
第一步,复制一份shop-basic
源码,将其名字修改为shop-swagger-ui
,然后对应包和文件中的信息也记得修改,本篇后续所有操作均在shop-swagger-ui
这一Module中进行。
第二步,在shop-swagger-ui
的POM文件中新增如下依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!-- MyBatis 生成器 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> </dependency> <!--Swagger-UI API文档--> <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>
|
注意,mybatis-generator-core
的版本必须从1.3.3修改为1.3.7,否则后续在生成API文档的时候会出现异常问题,以及新生成的mapper文件无法覆盖旧文件的情况。
第三步,在config包内新建一个名为Swagger2Config的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| /** * Swagger2 API文档相关配置 */ @Configuration @EnableSwagger2 public class Swagger2Config { @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() //为当前包下controller生成API文档 .apis(RequestHandlerSelectors.basePackage("com.kenbings.shop.shopswaggerui.controller")) //为有@Api注解的Controller生成API文档 // .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) //为有@ApiOperation注解的方法生成API文档 // .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .paths(PathSelectors.any()) .build(); }
private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("整合SwaggerUI") .description("myshop-all") .contact("kenbings") .version("1.0") .build(); } }
|
请注意,Swagger UI对生成API文档的范围有三种选择,分别如下所示:
(1)生成指定包下类的API文档:
1
| .apis(RequestHandlerSelectors.basePackage("com.kenbings.shop.shopswaggerui.controller"))
|
(2)生成有指定注解的类的API文档:
1
| .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
|
(3)生成有指定注解的方法的API文档:
1
| .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
第四步,给需要生成的Controller类添加Swagger注解,此处选择之前使用的品牌管理PmsBrandController类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| /** * 品牌管理Controller */ @Api(tags = "PmsBrandController",description = "商品品牌管理") @RestController @RequestMapping("/brand") public class PmsBrandController { @Autowired private PmsBrandService pmsBrandService;
private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);
/** * 查询所有的品牌信息 */ @ApiOperation("获取所有的品牌信息") @GetMapping("/listAll") public CommonResult<List<PmsBrand>> getBrandList(){ return CommonResult.success(pmsBrandService.listAllBrand()); }
/** * 创建一个新品牌 */ @ApiOperation("添加品牌") @PostMapping("/create") public CommonResult createBrand(@RequestBody PmsBrand pmsBrand){ CommonResult commonResult; int count = pmsBrandService.createBrand(pmsBrand); if(count==1){ commonResult = CommonResult.success(pmsBrand); LOGGER.debug("品牌创建成功:{}",pmsBrand); }else{ commonResult = CommonResult.failed("品牌创建失败"); LOGGER.debug("品牌创建失败:{}",pmsBrand); } return commonResult; }
/** * 修改一个品牌信息 */ @ApiOperation("更新指定id的品牌信息") @PostMapping("/update/{id}") public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDTO, BindingResult result){ CommonResult commonResult; if(result.hasErrors()){ commonResult = CommonResult.failed(result.getFieldError().getDefaultMessage()); return commonResult; } int count = pmsBrandService.updateBrand(id,pmsBrandDTO); if(count==1){ commonResult = CommonResult.success(pmsBrandDTO); LOGGER.debug("品牌修改成功:{}",pmsBrandDTO); }else{ commonResult = CommonResult.failed("品牌修改失败"); LOGGER.debug("品牌修改失败:{}",pmsBrandDTO); } return commonResult; }
/** * 删除一个品牌 */ @ApiOperation("删除指定id的品牌") @PostMapping("/delete/{id}") public CommonResult deleteBrand(@PathVariable("id") Long id){ CommonResult commonResult; int count = pmsBrandService.deleteBrand(id); if(count==1){ commonResult = CommonResult.success(null); LOGGER.debug("品牌删除成功:{}",id); }else{ commonResult = CommonResult.failed("品牌修改失败"); LOGGER.debug("品牌删除失败:{}",id); } return commonResult; }
/** * 分页查询品牌信息 */ @ApiOperation("分页查询品牌列表") @GetMapping("/list") public CommonResult<CommonPage<PmsBrand>> listBrand( @RequestParam(value = "pageNum",defaultValue = "1") @ApiParam("页码")Integer pageNum, @RequestParam(value = "pageSize",defaultValue = "5") @ApiParam("每页数量") Integer pageSize ){ List<PmsBrand> pmsBrands = pmsBrandService.listBrand(pageNum, pageSize); return CommonResult.success(CommonPage.restPage(pmsBrands)); }
/** * 获取某个品牌信息 */ @ApiOperation("获取指定id的品牌详情") @GetMapping("/{id}") public CommonResult<PmsBrand> getBrand(@PathVariable("id")Long id){ return CommonResult.success(pmsBrandService.getBrand(id)); } }
|
这里我们充分使用了@Api
、@ApiOperation
和@ApiParam
注解,没有使用到@ApiModelProperty
注解,那是因为@ApiModelProperty
注解用于修饰实体类的属性,我们如果要使用它,就要修改MyBatis Generator注释的生成规则。
第五步,修改MyBatis Generator注释的生成规则。在前面我们说过,CommentGenerator
类是自定义注释生成器,我们可以修改addFieldComment
方法,使其可以生成Swagger的@ApiModelProperty
注解来取代原来的方法注释。同时还需要添加addJavaFileComment
方法,使其能在import中导入@ApiModelProperty
,否则需要手动导入该类,这在需要生成大量实体类时,是一件非常痛苦的事情。
CommentGenerator
类中的代码修改为如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| /** * 自定义注释生成器 */ public class CommentGenerator extends DefaultCommentGenerator { private boolean addRemarkComments = false; private static final String EXAMPLE_SUFFIX="Example"; 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)) { //数据库中特殊字符需要转义 if(remarks.contains("\"")){ remarks = remarks.replace("\"","'"); } //给model的字段添加swagger注解 field.addJavaDocLine("@ApiModelProperty(value = \""+remarks+"\")"); } }
@Override public void addJavaFileComment(CompilationUnit compilationUnit) { super.addJavaFileComment(compilationUnit); //只在model中添加swagger注解类的导入 if(!compilationUnit.isJavaInterface()&&!compilationUnit.getType().getFullyQualifiedName().contains(EXAMPLE_SUFFIX)){ compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME)); } } }
|
第六步,在generatorConfig.xml
文件中新增一行配置信息:
1 2
| <!--生成mapper.xml时覆盖原文件--> <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
|
注意配置项的放置位置:
第七步,执行Generator类中的main方法,可以看到此时会重新生成mbg中的代码。
可以看到新生成的PmsBrand类里面,已经根据数据库注释自动添加了@ApiModelProperty
注解:
第八步,启动项目,访问Swagger-UI接口文档地址,即浏览器访问http://localhost:8080/swagger-ui.html
链接,效果如下:
点击添加品牌按钮,可以看到里面已经显示从@ApiModelProperty
文件中生成的说明信息:
点击分页查询品牌列表,可以看到返回结果也已经进行了说明:
同时开发者可以直接在文档上进行接口测试,这里以查询id为1的品牌详情信息为例进行说明:
这样本篇关于整合Swagger-UI实现在线API文档的学习就完成了,后续介绍如何整合单机版Redis实现缓存这一功能。本篇笔记源码,可以点击 这里 进行阅读。