最近开始看后端的东西,记录下学习笔记吧。
一、Swagger定义:http://swagger.io(官网)
Swagger是一个简单但功能强大的API表达工具。它具有地球上最大的API工具生态系统,数以千计的开发人员,使用几乎所有的现代编程语言,都在支持和使用Swagger。使用Swagger生成API,我们可以得到交互式文档,自动生成代码的SDK以及API的发现特性等。
现在,Swagger已经帮助包括Apigee, Getty图像, Intuit, LivingSocial, McKesson, 微软, Morningstar和PayPal等世界知名企业建立起了一套基于RESTful API的完美服务系统。
2.0版本已经发布,Swagger变得更加强大。值得感激的是,Swagger的源码100%开源在github。
Swagger是一组开源项目,其中主要要项目如下:
1. Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。
2. Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架进行集成。
3. Swagger-js: 用于JavaScript的Swagger实现。
4. Swagger-node-express: Swagger模块,用于node.js的Express web应用框架。
5. Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。
6. Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。
二、作用
1、接口文档的在线自动生成
2、功能测试
三、集成
1、maven方式 在pom.xml中增加dependency
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
2、创建Swagger2配置类(看其他的贴子中写要和Application同级目录,但是我没有放在同一级别也可以,不知原因,知道原因的可以给我留言,互相学习。)
package com.betty.miaosha.config;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Contact;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/*
* Create by BettyLi on 2019/12/1 14:40
*
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
@Bean
public Docket petApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.apis(RequestHandlerSelectors.basePackage("com.betty.miaosha.controller")) //指定提供接口所在的基包
.paths(PathSelectors.any())
.build();
}
/**
* 该套 API 说明,包含作者、简介、版本、host、服务URL
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Betty Swagger学习")
.version("1.0")
//.termsOfServiceUrl("localhost:8090/betty")
.description("betty demo")
.build();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(
"classpath:/static/");
// 解决 SWAGGER 404报错
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
不加addResourceHandlers的话,我这边是报错no mapper错误,也有的说是404,我直接就加上了。
做好这些就可以在Controller中添加文档内容了。
3、在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,描述的主要来源是函数的命名,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。
Swagger使用的注解及其说明:
@Api:用在类上,说明该类的作用。
@ApiOperation:注解来给API增加方法说明。
@ApiImplicitParams : 用在方法上包含一组参数说明。
@ApiImplicitParam:用来注解来给方法入参增加说明。
@ApiResponses:用于表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
l code:数字,例如400
l message:信息,例如"请求参数没填好"
l response:抛出异常的类
@ApiModel:描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)
l @ApiModelProperty:描述一个model的属性
注意:@ApiImplicitParam的参数说明:
paramType:指定参数放在哪个地方 | header:请求参数放置于Request Header,使用@RequestHeader获取 query:请求参数放置于请求地址,使用@RequestParam获取 path:(用于restful接口)-->请求参数的获取:@PathVariable body:(不常用) form(不常用) |
name:参数名 |
|
dataType:参数类型 |
|
required:参数是否必须传 | true | false |
value:说明参数的意思 |
|
defaultValue:参数的默认值 |
|
例:
package com.betty.miaosha.controller; import com.alibaba.druid.util.StringUtils; import com.betty.miaosha.controller.viewobject.UserVO; import com.betty.miaosha.error.BusinessException; import com.betty.miaosha.error.EmBusinessError; import com.betty.miaosha.response.CommonReturnType; import com.betty.miaosha.service.UserService; import com.betty.miaosha.service.model.UserModel; import io.swagger.annotations.*; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import sun.misc.BASE64Encoder; import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; /* * Create by BettyLi on 2019/11/21 15:46 * */ @RestController @MapperScan("com.betty.miaosha.dao") @RequestMapping("/user") @Api(value = "UserControllerBetty测试", tags = { "ueser interface" }) //DEFAULT_ALLOWED_HEADERS 允许跨域传输所有的headers参数,将用于使用token放入header域做session共享的跨域请求 @CrossOrigin(allowCredentials = "true",allowedHeaders = "*") public class UserController extends BaseController{ @Autowired private UserService userService; @Autowired private HttpServletRequest httpServletRequest; @PostMapping("/login") @ApiOperation(value = "登录接口") @ApiImplicitParams({ @ApiImplicitParam(name="telphone",value="手机号",required=true,paramType="query"), @ApiImplicitParam(name="password",value="密码",required=false,paramType="query"), }) @ApiResponses({ @ApiResponse(code=400,message="请求参数没填好"), @ApiResponse(code=404,message="请求路径没有或页面跳转路径不对") }) public CommonReturnType login( @RequestParam("telphone") String telphone, @RequestParam("password") String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException { //入参校验 if(org.apache.commons.lang3.StringUtils.isEmpty(telphone)|| org.apache.commons.lang3.StringUtils.isEmpty(password)){ throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR); } //用户登录服务用来校验登录是否合法 UserModel userModel = userService.validateLogin(telphone,this.EncodeByMD5(password)); //将登录凭证加入到用户登录成功的session内 this.httpServletRequest.getSession().setAttribute("IS_LOGIN",true); this.httpServletRequest.getSession().setAttribute("LOGIN_USER",userModel); return CommonReturnType.create(null); } @PostMapping("/register") @ApiOperation(value = "注册接口") public CommonReturnType register(@RequestParam("name") String name, @RequestParam("telphone") String telphone, @RequestParam("password") String password, @RequestParam("registerMode") String registerMode, @RequestParam("gender") Integer gender, @RequestParam("age") Integer age, @RequestParam("optCode") String optCode) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException { //验证手机号和对应的optcode相符合 String intSessionOtpCode = (String)this.httpServletRequest.getSession().getAttribute(telphone); if(!StringUtils.equals(optCode,intSessionOtpCode)){ throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"短信验证码不正确"); } //用户的注册流程 UserModel userModel = new UserModel(); userModel.setTelphone(telphone); userModel.setName(name); userModel.setPassword(this.EncodeByMD5(password)); userModel.setAge(age); userModel.setGender(new Byte(String.valueOf(gender.intValue()))); userModel.setRegisterMode(registerMode); userService.register(userModel); return CommonReturnType.create(null); } public String EncodeByMD5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException { //确定计算方法 MessageDigest md5 = MessageDigest.getInstance("MD5"); BASE64Encoder base64Encoder = new BASE64Encoder(); //加密字符串 String newStr = base64Encoder.encode(md5.digest(str.getBytes("utf-8"))); return newStr; } @GetMapping("/get/{id}") @ApiOperation(value = "根据id获取用户信息") public CommonReturnType getUser(@PathVariable("id")int id) throws BusinessException { //调用service服务获取对应id的用户对象并返回给前端 UserVO userVO = new UserVO(); UserModel userModel = userService.getUserById(id); if(userModel==null){ throw new BusinessException(EmBusinessError.USER_NOT_EXIST); //return CommonReturnType.create(userModel,"fail"); }else{ //将核心领域模型用户对象转化为可供UI使用的viewobject BeanUtils.copyProperties(userModel,userVO); } return CommonReturnType.create(userVO); } @PostMapping(value = "/getotp",consumes = {"application/x-www-form-urlencoded"}) @ApiOperation(value = "获取验证码") private CommonReturnType getOtp(@RequestParam("telphone")String telphone){ //需要按照一定的规则生成OTP验证码 Random random = new Random(); int randonInt = random.nextInt(99999); randonInt = randonInt+10000; String otpCode = String .valueOf(randonInt); //将OTP验证码同对应用户的手机关联 使用httpsession的方式绑定他的手机号与OTPCODE httpServletRequest.getSession().setAttribute(telphone,otpCode); //将OTP验证码通过短信通道发送给用户,省略 System.out.println("telphone="+telphone+"&otpCode="+otpCode); return CommonReturnType.create(null); } }
完成上述代码添加上,启动Spring Boot程序,访问:http://localhost:server.port/server.servlet.context-path/swagger-ui.html
注:设置server.port 和 server.servlet.context-path要加上。我就是因为忘记了path坑了很久。
到此基本完成。
遇到的问题也在上面写了,还有一个是 点击行不能展开,只能点击右上角的 List Operations 和 Expand Operations 进行所有方法的 展开和关闭, 使用起来特别麻烦.,最后发现在API注解上的属性中有 value 和 tags 两个属性, Value的值不会展示在 UI界面上, tags会展示在界面上, 如果tags 中的值设置为中文, 那么 下面的方法名点击将不能被展开,改成英文之后正常.value 值是否为中文不影响.