在解决高并发的学习中,接触到swagger2.是一个接口文档的解决方案.开始自己学习在已有的项目上进行部署.将学习到的与遇到的问题进行整理,希望对大家以及以后的工作有所帮助.
使用swagger2需要引入swagger2的pom坐标,特别注明,两个pom坐标的版本需要相同.
<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>
此处的swagger2.version可以直接RELEASE的版本,将自动使用最新版本.
在Spring boot上集成swagger2需要使用Configuration注解进行注入,此处给出一个范例.
package com.mingcloud.az.common; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * @author Relic * @desc swagger2配置类 * @date 2019-02-05 15:59 */ @EnableSwagger2 @Configuration public class Swagger2Configuration { @Bean public Docket controllerApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(new ApiInfoBuilder().title("xxxxx接口文档").description("前后端分离使用过的接口文档") .contact(new Contact("Relic", null, null)).version("版本号:1.0").build()) .select().apis(RequestHandlerSelectors.basePackage("com.mingcloud.az.controller")) .paths(PathSelectors.any()).build(); } }
swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。
@Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI界面上也看到,所以不需要配置" @ApiOperation:用在请求的方法上,说明方法的用途、作用 value="说明方法的用途、作用" notes="方法的备注说明" @ApiImplicitParams:用在请求的方法上,表示一组参数说明 @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面 name:参数名 value:参数的汉字说明、解释 required:参数是否必须传 paramType:参数放在哪个地方 · header --> 请求参数的获取:@RequestHeader · query --> 请求参数的获取:@RequestParam · path(用于restful接口)--> 请求参数的获取:@PathVariable · body(不常用) · form(不常用) dataType:参数类型,默认String,其它值dataType="Integer" defaultValue:参数的默认值 @ApiResponses:用在请求的方法上,表示一组响应 @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 code:数字,例如400 message:信息,例如"请求参数没填好" response:抛出异常的类 @ApiModel:用于响应类上,表示一个返回响应数据的信息 (这种一般用在post创建的时候,使用@RequestBody这样的场景, 请求参数无法使用@ApiImplicitParam注解进行描述的时候) @ApiModelProperty:用在属性上,描述响应
此处需要引入一个Restful风格接口的概念.
URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。
识别(identify)、 表示(represent) 、交互(interact with)。
1. REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口);
2. Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。比如:
http://api.qc.com/v1/newsfeed: 获取某人的新闻推送;
http://api.qc.com/v1/friends: 获取某人的好友列表;
http://api.qc.com/v1/profile: 获取某人的详细信息;
3. 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转:
GET 用来获取资源,
POST 用来新建资源(也可以用于更新资源),
PUT 用来更新资源,
DELETE 用来删除资源。比如:
DELETE http://api.qc.com/v1/friends: 删除某人的好友 (在http parameter指定好友id)
POST http://api.qc.com/v1/friends: 添加好友
UPDATE http://api.qc.com/v1/profile: 更新个人资料
4. Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据(on-wire data compression)。
5. 用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等。
1、REST 是面向资源的,这个概念非常重要,而资源是通过 URI 进行暴露。
比如:左边是错误的设计,而右边是正确的
GET /rest/api/getDogs --> GET /rest/api/dogs 获取所有小狗狗 GET /rest/api/addDogs --> POST /rest/api/dogs 添加一个小狗狗 GET /rest/api/editDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗 GET /rest/api/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗
2、REST很好地利用了HTTP本身就有的一些特征,如HTTP动词、HTTP状态码、HTTP报头等等。
GET 获取一个资源 POST 添加一个资源 PUT 修改一个资源 DELETE 删除一个资源
200 OK 400 Bad Request 500 Internal Server Error
Authorization 认证报头 Cache-Control 缓存报头 Cnotent-Type 消息体类型报头 ......
在控制层上加上注解.
package com.mingcloud.az.controller; import com.mingcloud.az.common.ConfigurationTypeEnum; import com.mingcloud.az.common.Result; import com.mingcloud.az.entity.ConfigurationEntity; import com.mingcloud.az.service.ConfigurationService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author xyc */ @Api("相关属性(时间.等)的配置") @RestController @RequestMapping("/configuration") public class ConfigurationController { @Resource private ConfigurationService configurationService; @ApiOperation("根据条件获取配置") @GetMapping("/doGetConfig.do") public Result getConfig(ConfigurationEntity entity) { Result result; try { entity.setTypeId(ConfigurationTypeEnum.getConfigurationByType(entity.getTypeStr())); result = configurationService.getConfig(entity); } catch (Exception e) { e.printStackTrace(); result = new Result(false, e.getMessage()); } return result; } /** * 更新配置参数接口,如需更新的typeId数据库没有,则新建,如果存在就更新 * * @param entity 配置实体类 * @return com.mingcloud.az.common.Result * @title updateConfig * @date 2019/1/17 15:48 */ @PutMapping("/doUpdateConfig.do") public Result updateConfig(ConfigurationEntity entity) { Result result; try { entity.setTypeId(ConfigurationTypeEnum.getConfigurationByType(entity.getTypeStr())); result = configurationService.updateConfig(entity); } catch (Exception e) { e.printStackTrace(); result = new Result(false, e.getMessage()); } return result; } }
实体类上添加上注解
package com.mingcloud.az.entity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.*; import java.util.Date; /** * @author Relic */ @Getter @Setter @Builder @ToString @NoArgsConstructor @AllArgsConstructor @ApiModel("配置实体类") public class ConfigurationEntity extends BaseEntity { @ApiModelProperty(hidden = true) private Long id; @ApiModelProperty(value = "类型id") private Integer typeId; @ApiModelProperty("备注") private String memo; @ApiModelProperty(value = "额外id1") private Integer extraId1; @ApiModelProperty(value = "额外id2") private Integer extraId2; @ApiModelProperty(value = "额外id3") private Integer extraId3; @ApiModelProperty(value = "天数") private Integer extraInt1; @ApiModelProperty(value = "额外整数2") private Integer extraInt2; @ApiModelProperty(value = "额外整数3") private Integer extraInt3; @ApiModelProperty("额外字符串1") private String extraVarChar1; @ApiModelProperty("额外字符串2") private String extraVarChar2; @ApiModelProperty("额外字符串3") private String extraVarChar3; @ApiModelProperty("类型名称") private String typeStr; @ApiModelProperty("修改日期") private Date modificationDate; @ApiModelProperty(value = "修改用户id") private Integer modificationUserId; }
最后,启动项目,访问 http://ip:port/项目名/swagger-ui.html页面
swagger2一个很实用的功能就就是在测试接口功能上.点击接口上的try it out.然后填写参数,点击execute.
可以直接在编写前端代码之前直接进行测试.
下面说几个遇到的坑- -.
1.访问swagger2-ui.html的时候出现弹框.
一开始以为是context-path的问题.去掉context-path的确能够访问,但是不是长久之计.
后来发现只要清除缓存之后,即可解决这个问题.
2.访问swagger2-ui.html界面时,后台一直报错:Illegal DefaultValue null for parameter type integer
原因是由于swagger2的bug,在没有给定integer与long类型的变量默认值的情况下,默认是""值,所以强转失败.对程序本身没有什么影响,但是毕竟本人是个强迫症患者= =.所以在调高日志打印级别为error.
logging.level.io.swagger.models.parameters.AbstractSerializableParameter: error
顺利解决.