前言
平时做接口测试接触最多的就是Swagger,之前还用过 YApi,但YApi被爆出漏洞后,就被我们开发抛弃了。最近对swagger的搭建有一定兴趣,所以实践了一下。
操作
1、导入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2、编写Swagger配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* @author xcj
* @date 2023/2/28 16:20
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* 设置多个:
*
* @return
* @Bean public Docket appApi() {
* <p>
* List<Parameter> pars = new ArrayList<>();
* ParameterBuilder token = new ParameterBuilder();
* token.name("token").description("用户令牌").modelRef(new ModelRef("string")).parameterType("header").required(false)
* .build();
* pars.add(token.build());
* <p>
* return new Docket(DocumentationType.SWAGGER_2).select().paths(regex("/app/.*")).build()
* .globalOperationParameters(pars).apiInfo(pdaApiInfo()).useDefaultResponseMessages(false)
* .enable(enableSwagger)
* .groupName("appApi");
* <p>
* }
* @Bean public Docket adminApi() {
* <p>
* List<Parameter> pars = new ArrayList<>();
* ParameterBuilder token = new ParameterBuilder();
* token.name("token").description("用户令牌").modelRef(new ModelRef("string")).parameterType("header").required(false)
* .build();
* pars.add(token.build());
* return new Docket(DocumentationType.SWAGGER_2).select().paths(regex("/admin/.*")).build()
* .globalOperationParameters(pars).apiInfo(pdaApiInfo()).useDefaultResponseMessages(false)
* .enable(enableSwagger)
* .groupName("adminApi");
* <p>
* }
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.basePackage("com.xcj.jmeterdemo.controller")).paths(PathSelectors.any())
.build().globalOperationParameters(setHeaderToken());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("action-swagger").description("swagger接口文档").termsOfServiceUrl("")
.version("1.0").build();
}
/**
* @param
* @Description: 设置swagger文档中全局参数
* @Date: 2020/9/11 10:15
* @return: java.util.List<springfox.documentation.service.Parameter>
*/
private List<Parameter> setHeaderToken() {
List<Parameter> pars = new ArrayList<>();
ParameterBuilder userId = new ParameterBuilder();
userId.name("token").description("用户TOKEN").modelRef(new ModelRef("string")).parameterType("header")
.required(true).build();
pars.add(userId.build());
return pars;
}
}
3、为VO、DTO添加注解
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author xcj
* @date 2022/8/4 15:30
*/
@Data
@ApiModel("订单对象")
public class OrderDto {
@ApiModelProperty("订单号")
private String orderId;
@ApiModelProperty("商品名称")
private String productName;
@ApiModelProperty("商品数量")
private int productNumber;
}
package com.xcj.jmeterdemo.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author xcj
* @date 2022/2/12 10:28
*/
@Data
@ApiModel("统一响应结果")
public class ResultVo<T> {
@ApiModelProperty("响应码")
private int code;
@ApiModelProperty("响应信息")
private String msg;
@ApiModelProperty("响应对象")
private T data;
}
4、为Controller添加注解
package com.xcj.jmeterdemo.controller;
import com.xcj.jmeterdemo.entity.OrderDto;
import com.xcj.jmeterdemo.entity.ProductDto;
import com.xcj.jmeterdemo.enums.AllEnum;
import com.xcj.jmeterdemo.vo.ResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Controller
@Api(value = "乱七八糟的接口集",tags = {"乱七八糟的接口集"})
public class MainController {
final String TOKEN = "SnhHsOcabQ66CeaI";
Map<String, Integer> productMap = new HashMap<String, Integer>() {{
put("牛奶", Integer.valueOf("1"));
}};
ArrayList<OrderDto> orderDtoList = new ArrayList<>();
/**
* 账号密码登录
*
* @param name
* @param password
* @return
*/
@PostMapping("login")
@ResponseBody
@ApiOperation("账号密码登录")
public ResultVo login(String name, String password) {
ResultVo resultVo = new ResultVo();
resultVo.setCode(200);
resultVo.setMsg("获取下单身份token成功");
Map map = new HashMap();
map.put("token", TOKEN);
resultVo.setData(map);
return resultVo;
}
/**
* 检查库存
*
* @param productName
* @param number
* @return
*/
@GetMapping("checkStock")
@ResponseBody
@ApiOperation("检查库存")
public ResultVo checkStock(String productName, int number) {
ResultVo resultVo = new ResultVo();
Integer num = productMap.get(productName);
if (num != null) {
if (number <= num) {
resultVo.setCode(200);
resultVo.setMsg("库存充足");
resultVo.setData("true");
} else {
resultVo.setCode(AllEnum.Not_Enough_Stock.getCode());
resultVo.setMsg(AllEnum.Not_Enough_Stock.getMsg());
resultVo.setData("false");
}
} else {
resultVo.setCode(AllEnum.Not_Exist_Stock.getCode());
resultVo.setMsg(AllEnum.Not_Exist_Stock.getMsg());
resultVo.setData(productMap);
}
return resultVo;
}
/**
* 添加商品库存
*
* @param productDto
* @return
*/
@PostMapping("addProductStock")
@ResponseBody
@ApiOperation("添加商品库存")
public ResultVo addProductStock(@RequestBody ProductDto productDto) {
ResultVo resultVo = new ResultVo();
Integer number = productMap.get(productDto.getName());
if (number != null && number > 0) {
number += productDto.getNumber();
productMap.put(productDto.getName(), number);
resultVo.setCode(200);
resultVo.setMsg("添加库存成功");
resultVo.setData(productMap);
} else {
productMap.put(productDto.getName(), productDto.getNumber());
resultVo.setCode(200);
resultVo.setMsg("新增商品成功");
resultVo.setData(productMap);
}
return resultVo;
}
/**
* 更新库存
*
* @param productDto
* @return
*/
@PutMapping("updateProductStock")
@ResponseBody
@ApiOperation("更新库存")
public ResultVo updateProductStock(@RequestBody ProductDto productDto) {
ResultVo resultVo = new ResultVo();
Integer num = productMap.get(productDto.getName());
if (num != null) {
productMap.put(productDto.getName(), productDto.getNumber());
resultVo.setCode(200);
resultVo.setMsg("修改" + productDto.getName() + "库存信息成功,该商品剩余库存数量为:" + productDto.getNumber());
resultVo.setData(productMap);
} else {
resultVo.setCode(AllEnum.Failed_To_Modify_Commodity_Quantity.getCode());
resultVo.setMsg(AllEnum.Failed_To_Modify_Commodity_Quantity.getMsg());
resultVo.setData(false);
}
return resultVo;
}
/**
* 消耗库存
*
* @param productName
* @return
*/
@DeleteMapping("removeProductStock")
@ResponseBody
@ApiOperation("消耗库存")
public ResultVo removeProductStock(String productName) {
ResultVo resultVo = new ResultVo();
Integer num = productMap.get(productName);
if (num != null) {
productMap.remove(productName);
resultVo.setCode(200);
resultVo.setMsg("移除商品:" + productName + "成功!");
resultVo.setData(productMap);
} else {
resultVo.setCode(AllEnum.Failed_To_Remove_Product.getCode());
resultVo.setMsg(AllEnum.Failed_To_Remove_Product.getMsg());
resultVo.setData(false);
}
return resultVo;
}
/**
* 展示所有商品库存
* @return
*/
@GetMapping(value = "showAllStock")
@ResponseBody
@ApiOperation("展示所有商品库存")
public ResultVo showAllStock(){
ResultVo resultVo = new ResultVo();
if (productMap!=null && productMap.size()!=0){
resultVo.setCode(200);
resultVo.setMsg("展示所有库存");
resultVo.setData(productMap);
}else {
resultVo.setCode(AllEnum.Inventory_Is_Empty.getCode());
resultVo.setMsg(AllEnum.Inventory_Is_Empty.getMsg());
}
return resultVo;
}
/**
* 预下单
*
* @param productDto
* @param authorization
* @return
*/
@PostMapping("preOrder")
@ResponseBody
@ApiOperation("预下单")
public ResultVo preOrder(ProductDto productDto, @RequestHeader("Authorization") String authorization) {
ResultVo resultVo = new ResultVo();
System.out.println(productDto.getName() + " " + productDto.getNumber() + " " + authorization);
if (productDto != null && productMap.get(productDto.getName()) != null){
if (TOKEN.equals(authorization)) {
if (productMap.get(productDto.getName()) >= productDto.getNumber()){
Map map = new HashMap();
String oId = new Date().getTime() + "";
map.put("orderId", oId);
resultVo.setCode(200);
resultVo.setMsg("身份校验通过," + productDto.getName() + "成功预下单" + productDto.getNumber() + "份!");
resultVo.setData(map);
OrderDto orderDto = new OrderDto();
orderDto.setOrderId(oId);
orderDto.setProductName(productDto.getName());
orderDto.setProductNumber(productDto.getNumber());
orderDtoList.add(orderDto);
}else{
resultVo.setCode(AllEnum.Not_Enough_Stock.getCode());
resultVo.setMsg(AllEnum.Not_Enough_Stock.getMsg());
}
} else {
resultVo.setCode(AllEnum.Authentication_Failed.getCode());
resultVo.setMsg(AllEnum.Authentication_Failed.getMsg());
}
}else {
resultVo.setCode(AllEnum.Illegal_Request_Parameters.getCode());
resultVo.setMsg(AllEnum.Illegal_Request_Parameters.getMsg());
}
return resultVo;
}
/**
* 支付订单
*
* @param orderIdMap
* @return
*/
@PostMapping("payOrder")
@ResponseBody
@ApiOperation("支付订单")
public ResultVo payOrder(@RequestBody Map orderIdMap) {
System.out.println("orderIdMap:"+orderIdMap);
String orderId = String.valueOf(orderIdMap.get("orderId"));
System.out.println("orderId:" + orderId);
ResultVo resultVo = new ResultVo();
if (orderId != null && !"".equals(orderId)) {
if (orderDtoList.size()>0){
for (OrderDto orderDto : orderDtoList) {
if (orderId.equals(orderDto.getOrderId())) {
//库存数量
Integer stock = productMap.get(orderDto.getProductName());
if (stock != null && orderDto.getProductNumber() <= stock) {
productMap.put(orderDto.getProductName(),stock - orderDto.getProductNumber());
resultVo.setCode(200);
resultVo.setMsg("模拟支付成功!");
resultVo.setData(orderId);
}else{
resultVo.setCode(AllEnum.Simulated_Payment_Failed.getCode());
resultVo.setMsg(AllEnum.Simulated_Payment_Failed.getMsg());
}
}else{
resultVo.setCode(AllEnum.Not_Exist_OrderId.getCode());
resultVo.setMsg(AllEnum.Not_Exist_OrderId.getMsg());
}
}
}else {
resultVo.setCode(AllEnum.Not_Exist_OrderId.getCode());
resultVo.setMsg(AllEnum.Not_Exist_OrderId.getMsg());
}
}else {
resultVo.setCode(AllEnum.Illegal_Request_Parameters.getCode());
resultVo.setMsg(AllEnum.Illegal_Request_Parameters.getMsg());
}
return resultVo;
}
public static void main(String[] args) {
String format = new SimpleDateFormat("yyyyMMdd").format(new Date().getTime());
System.out.println(format);
}
}
5、应版本适配问题
springboot 2.6.3 swagger2 2.9.2
application.xml文件中添加:
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
6、效果如下:
访问地址:
ip:端口号/swagger-ui.html
其他 UI 对比
UI 1:
maven依赖
<!-- https://mvnrepository.com/artifact/com.zyplayer/swagger-mg-ui -->
<dependency>
<groupId>com.zyplayer</groupId>
<artifactId>swagger-mg-ui</artifactId>
<version>1.0.6</version>
</dependency>
访问地址:http://ip:端口/document.html
UI 2:
maven依赖
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>3.0.3</version>
</dependency>
访问地址:http://ip:端口/doc.html
评论区