概述
Swagger是一款RESTFUL接口的文档在线自动生成加功能测试的软件,提供描述、生产、消费和可视化RESTful Web Service。Swagger也是一个api文档维护组织,后来成为了OpenAPI(一个业界的api文档标准)标准的主要定义者,现在最新的版本为17年发布的Swagger3(OpenAPI3)。基于OpenAPI2的Swagger2已于2017年停止维护。
SpringFox是Spring社区维护的一个项目(非官方),帮助使用者将Swagger2集成到Spring中。常用于Spring中帮助开发者生成文档,并可以轻松的在SpringBoot中使用,目前已经支持OpenAPI3标准。
本文主要对SpringBoot2.x集成Swagger3进行简单总结,通过引入SpringFox来使用Swagger3,其中SpringBoot使用的2.4.5
版本。
一、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
二、编写配置类
package com.rtxtitanv.config;
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.oas.annotations.EnableOpenApi;
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.Collections;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.config.Swagger3Config
* @description Swagger3配置类
* @date 2021/6/7 12:47
*/
@Configuration
@EnableOpenApi
public class Swagger3Config {
/**
* 配置默认分组
*
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket defaultApi() {
// DocumentationType.OAS_30为Swagger3的文档类型
return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo()).select()
/*
* 通过apis和paths方法设置ApiSelector的构建规则
* ApiSelectorBuilder apis(Predicate<RequestHandler> selector)
* RequestHandlerSelectors.any():构建所有API
* RequestHandlerSelectors.none():所有API都不构建
* RequestHandlerSelectors.basePackage():构建指定包路径下的所有API
* RequestHandlerSelectors.withClassAnnotation():仅构建带有指定类注解的API
* RequestHandlerSelectors.withMethodAnnotation():仅构建带有指定方法注解的API
* ApiSelectorBuilder paths(Predicate<String> selector)
* PathSelectors.any():构建所有请求路径的API
* PathSelectors.none():所有请求路径的API都不构建
* PathSelectors.regex():仅构建正则匹配的请求路径的API
* PathSelectors.ant():仅构建与ant模式匹配的API
*/
.apis(RequestHandlerSelectors.basePackage("com.rtxtitanv.controller.other")).paths(PathSelectors.any())
.build();
}
/**
* 配置user分组
*
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket userApi() {
return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo())
// 通过securitySchemes和securityReferences方法进行JWT配置
.securitySchemes(Collections.singletonList(HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("JWT").build()))
.securityContexts(Collections.singletonList(SecurityContext.builder()
.securityReferences(Collections.singletonList(
SecurityReference.builder().scopes(new AuthorizationScope[0]).reference("JWT").build()))
.operationSelector(operationContext -> operationContext.requestMappingPattern().matches("/.*"))
.build()))
.select().apis(RequestHandlerSelectors.basePackage("com.rtxtitanv.controller.user"))
// groupName方法设置分组名称
.paths(PathSelectors.regex("/user/.*")).build().groupName("user");
}
/**
* 配置order分组
*
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket orderApi() {
return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo())
.securitySchemes(Collections.singletonList(HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("JWT").build()))
.securityContexts(Collections.singletonList(SecurityContext.builder()
.securityReferences(Collections.singletonList(
SecurityReference.builder().scopes(new AuthorizationScope[0]).reference("JWT").build()))
.operationSelector(operationContext -> operationContext.requestMappingPattern().matches("/.*"))
.build()))
.select().apis(RequestHandlerSelectors.basePackage("com.rtxtitanv.controller.order"))
.paths(PathSelectors.regex("/order/.*")).build().groupName("order");
}
/**
* 构建API文档基本信息
*
* @return springfox.documentation.service.ApiInfo
*/
private ApiInfo apiInfo() {
// 联系人信息:分别为作者、主页、邮箱
Contact contact = new Contact("RtxTitanV", "https://blog.csdn.net/RtxTitanV", "RtxTitanV@xxx.com");
// 构建API文档的详细信息:依次为API标题、API描述、API联系人信息、API版本、API许可、API许可Url
return new ApiInfoBuilder().title("SpringBoot2.x 集成 Swagger3").description("SpringBoot2.x 集成 Swagger3 测试文档")
.contact(contact).version("1.0.0").license("Apache 2.0")
.licenseUrl("https://www.apache.org/licenses/LICENSE-2.0").build();
}
}
配置类中每一个Docket对象都代表一个分组,Bean的名称不能相同,通过调用groupName(String groupName)
方法来设置分组名。以上配置了三个分组,分别为default、user、order三组,其中没有调用groupName(String groupName)
的Docket对象是默认分组配置,不同的分组可以配置不同的API文档基本信息(文档标题、描述、联系人信息等),这里主要是测试,就都配置的统一的API文档基本信息。另外user和order分组都配置了JWT认证,配置方式与Swagger2有所不同,配置JWT认证后在API文档中认证了Token之后,每次请求时在请求头都会携带该token。
Doket
类的方法Docket enable(boolean externallyConfiguredFlag)
可以控制Swagger的开启和关闭,可以根据不同环境进行动态的配置。配置项springfox.documentation.enabled
也可以控制Swagger的开启与关闭,设置为false可以关闭Swagger。
三、创建实体类
package com.rtxtitanv.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.model.User
* @description 用户实体类
* @date 2021/6/7 12:41
*/
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "User", description = "用户信息")
public class User implements Serializable {
private static final long serialVersionUID = -583023130164283193L;
@ApiModelProperty(value = "用户id")
private Long id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
}
package com.rtxtitanv.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.model.Order
* @description 订单实体类
* @date 2021/6/8 11:30
*/
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "Order", description = "订单信息")
public class Order implements Serializable {
private static final long serialVersionUID = -688022729580581140L;
@ApiModelProperty(value = "订单id")
private Long id;
@ApiModelProperty(value = "订单编号")
private String orderNumber;
@ApiModelProperty(value = "订单描述")
private String orderDescription;
@ApiModelProperty(value = "订单所属用户id")
private Long userId;
}
package com.rtxtitanv.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.model.CommonResult
* @description 通用响应类
* @date 2021/6/8 10:45
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "CommonResult", description = "通用响应对象")
public class CommonResult<T> implements Serializable {
private static final long serialVersionUID = 2622902426607852032L;
@ApiModelProperty(value = "响应码", required = true)
private int code;
@ApiModelProperty(value = "响应信息", required = true)
private String message;
@ApiModelProperty(value = "响应数据")
private T data;
public static <T> CommonResult<T> success(String message, T data) {
return new CommonResult<>(HttpStatus.OK.value(), message, data);
}
public static <T> CommonResult<T> invalidParameter(String message) {
return new CommonResult<>(HttpStatus.BAD_REQUEST.value(), message, null);
}
public static <T> CommonResult<T> notFound(String message) {
return new CommonResult<>(HttpStatus.NOT_FOUND.value(), message, null);
}
}
四、Controller层
分组default中的用于简单测试的Controller:
package com.rtxtitanv.controller.other;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.controller.other.TestController
* @description TestController
* @date 2021/6/7 12:47
*/
@Api(value = "TestController", tags = "简单测试", description = "用于简单测试的API")
@RequestMapping("/test")
@RestController
public class TestController {
@ApiOperation(value = "hello", notes = "一个简单的测试接口")
@ApiImplicitParam(value = "名称", name = "name", required = true, defaultValue = "world",
dataTypeClass = String.class)
@GetMapping("/hello/{name}")
public String hello(@PathVariable(value = "name") String name) {
return "hello " + name;
}
}
分组user中的Controller:
package com.rtxtitanv.controller.user;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.User;
import com.rtxtitanv.service.UserService;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
import java.util.List;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.controller.user.UserController
* @description UserController
* @date 2021/6/7 12:47
*/
@Api(value = "用户模块", tags = "用户管理", description = "用户的增删改查", protocols = "http")
@RequestMapping("/user")
@RestController
public class UserController {
@Resource
private UserService userService;
@ApiOperation(value = "创建用户", notes = "根据User对象保存用户")
@ApiImplicitParams(value = {
@ApiImplicitParam(value = "用户id", name = "id", required = true, defaultValue = "1", dataTypeClass = Long.class,
paramType = "query"),
@ApiImplicitParam(value = "用户名", name = "username", required = true, defaultValue = "admin",
dataTypeClass = String.class, paramType = "query"),
@ApiImplicitParam(value = "密码", name = "password", required = true, defaultValue = "admin",
dataTypeClass = String.class, paramType = "query")})
@ApiResponses(value = {@ApiResponse(code = 200, message = "保存用户成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class)})
@PostMapping("/save")
public CommonResult<User> saveUser(@ApiIgnore User user) {
return userService.saveUser(user);
}
@ApiOperation(value = "查询所有用户", notes = "查询所有用户")
@ApiResponses(value = {@ApiResponse(code = 200, message = "查询所有用户成功")})
@GetMapping("/findAll")
public CommonResult<List<User>> findUserAll() {
return userService.findUserAll();
}
@ApiOperation(value = "根据id查询用户", notes = "查询指定id用户")
@ApiImplicitParam(value = "用户id", name = "id", required = true, defaultValue = "1", dataTypeClass = Long.class)
@ApiResponses(value = {@ApiResponse(code = 200, message = "根据id查询用户成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class)})
@GetMapping("/findById/{id}")
public CommonResult<User> findUserById(@PathVariable(value = "id") Long id) {
return userService.findUserById(id);
}
@ApiOperation(value = "根据id更新用户", notes = "更新指定id用户")
@ApiResponses(value = {@ApiResponse(code = 200, message = "根据id更新用户成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class),
@ApiResponse(code = 404, message = "用户不存在", response = CommonResult.class)})
@PutMapping("/updateById")
public CommonResult<User> updateUserById(@RequestBody User user) {
return userService.updateUserById(user);
}
@ApiOperation(value = "根据id删除用户", notes = "删除指定id用户")
@ApiImplicitParam(value = "用户id", name = "id", required = true, defaultValue = "1", dataTypeClass = Long.class)
@ApiResponses(value = {@ApiResponse(code = 200, message = "根据id删除用户成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class),
@ApiResponse(code = 404, message = "用户不存在", response = CommonResult.class)})
@DeleteMapping("/deleteById/{id}")
public CommonResult<User> deleteUserById(@PathVariable(value = "id") Long id) {
return userService.deleteUserById(id);
}
@ApiOperation(value = "删除所有用户", notes = "删除所有用户")
@ApiResponses(value = {@ApiResponse(code = 200, message = "删除所有用户成功"),
@ApiResponse(code = 404, message = "用户不存在", response = CommonResult.class)})
@DeleteMapping("/deleteAll")
public CommonResult<List<User>> deleteUserAll() {
return userService.deleteUserAll();
}
}
分组order中的Controller:
package com.rtxtitanv.controller.order;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.Order;
import com.rtxtitanv.service.OrderService;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
import java.util.List;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.controller.order.OrderController
* @description OrderController
* @date 2021/6/8 11:31
*/
@Api(value = "订单模块", tags = "订单管理", description = "订单的增删改查", protocols = "http")
@RequestMapping("/order")
@RestController
public class OrderController {
@Resource
private OrderService orderService;
@ApiOperation(value = "创建订单", notes = "根据Order对象保存订单")
@ApiImplicitParams(value = {
@ApiImplicitParam(value = "订单id", name = "id", required = true, defaultValue = "1", dataTypeClass = Long.class,
paramType = "query"),
@ApiImplicitParam(value = "订单编号", name = "orderNumber", required = true, defaultValue = "780829537365759918",
dataTypeClass = String.class, paramType = "query"),
@ApiImplicitParam(value = "订单描述", name = "orderDescription", required = true, defaultValue = "二两牛肉面,微辣,多放点香菜",
dataTypeClass = String.class, paramType = "query"),
@ApiImplicitParam(value = "订单所属用户id", name = "userId", required = true, defaultValue = "1",
dataTypeClass = Long.class, paramType = "query")})
@ApiResponses(value = {@ApiResponse(code = 200, message = "保存订单成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class)})
@PostMapping("/save")
public CommonResult<Order> saveOrder(@ApiIgnore Order order) {
return orderService.saveOrder(order);
}
@ApiOperation(value = "查询所有订单", notes = "查询所有订单")
@ApiResponses(value = {@ApiResponse(code = 200, message = "查询所有订单成功")})
@GetMapping("/finAll")
public CommonResult<List<Order>> findOrderAll() {
return orderService.findOrderAll();
}
@ApiOperation(value = "根据id更新订单", notes = "更新指定id订单")
@ApiResponses(value = {@ApiResponse(code = 200, message = "根据id更新订单成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class),
@ApiResponse(code = 404, message = "订单不存在", response = CommonResult.class)})
@PutMapping("/updateById")
public CommonResult<Order> updateOrderById(@RequestBody Order order) {
return orderService.updateOrderById(order);
}
@ApiOperation(value = "根据id删除订单", notes = "删除指定id订单")
@ApiImplicitParam(value = "订单id", name = "id", required = true, defaultValue = "1", dataTypeClass = Long.class)
@ApiResponses(value = {@ApiResponse(code = 200, message = "根据id删除订单成功"),
@ApiResponse(code = 400, message = "无效参数", response = CommonResult.class),
@ApiResponse(code = 404, message = "订单不存在", response = CommonResult.class)})
@DeleteMapping("/deleteById/{id}")
public CommonResult<Order> deleteOrderById(@PathVariable(value = "id") Long id) {
return orderService.deleteOrderById(id);
}
}
这里仍然使用的Swagger的文档注解,是因为Swagger3(OpenAPI3)的
@Tag
注解有点问题没有生效,在Swagger-UI上,Controller上@Tag
的name
属性表示的Controller的标题在和增删改查接口是分开的,并没有在同一个折叠面板中,所以还是换回了Swagger2的注解。
五、Service层
package com.rtxtitanv.service;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.User;
import java.util.List;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.service.UserService
* @description UserService
* @date 2021/6/7 12:48
*/
public interface UserService {
/**
* 保存用户
*
* @param user 用户参数
* @return CommonResult<User>
*/
CommonResult<User> saveUser(User user);
/**
* 查询所有用户
*
* @return CommonResult<List<User>>
*/
CommonResult<List<User>> findUserAll();
/**
* 根据id查询用户
*
* @param id 用户id
* @return CommonResult<User>
*/
CommonResult<User> findUserById(Long id);
/**
* 根据id更新用户
*
* @param user 用户参数
* @return CommonResult<User>
*/
CommonResult<User> updateUserById(User user);
/**
* 根据id删除用户
*
* @param id 用户id
* @return CommonResult<User>
*/
CommonResult<User> deleteUserById(Long id);
/**
* 删除所有用户
*
* @return CommonResult<List<User>>
*/
CommonResult<List<User>> deleteUserAll();
}
package com.rtxtitanv.service.impl;
import com.rtxtitanv.exception.InvalidParameterException;
import com.rtxtitanv.exception.NotFoundException;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.User;
import com.rtxtitanv.service.UserService;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.service.impl.UserServiceImpl
* @description UserService实现类
* @date 2021/6/7 12:49
*/
@Service
public class UserServiceImpl implements UserService {
/**
* 创建线程安全的Map,模拟用户信息的存储
*/
private static final Map<Long, User> USER_MAP = Collections.synchronizedMap(new HashMap<>());
@Override
public CommonResult<User> saveUser(User user) {
if (user.getId() <= 0) {
throw new InvalidParameterException("无效参数");
}
USER_MAP.put(user.getId(), user);
return CommonResult.success("保存用户成功", user);
}
@Override
public CommonResult<List<User>> findUserAll() {
return CommonResult.success("查询所有用户成功", new ArrayList<>(USER_MAP.values()));
}
@Override
public CommonResult<User> findUserById(Long id) {
if (id <= 0) {
throw new InvalidParameterException("无效参数");
}
return CommonResult.success("根据id查询用户成功", USER_MAP.get(id));
}
@Override
public CommonResult<User> updateUserById(User user) {
if (user.getId() <= 0) {
throw new InvalidParameterException("无效参数");
}
if (USER_MAP.get(user.getId()) == null) {
throw new NotFoundException("用户不存在");
}
user = USER_MAP.get(user.getId()).setUsername(user.getUsername()).setPassword(user.getPassword());
return CommonResult.success("根据id更新用户成功", user);
}
@Override
public CommonResult<User> deleteUserById(Long id) {
if (id <= 0) {
throw new InvalidParameterException("无效参数");
}
if (USER_MAP.get(id) == null) {
throw new NotFoundException("用户不存在");
}
return CommonResult.success("根据id删除用户成功", USER_MAP.remove(id));
}
@Override
public CommonResult<List<User>> deleteUserAll() {
if (USER_MAP.isEmpty()) {
throw new NotFoundException("用户不存在");
}
ArrayList<User> users = new ArrayList<>(USER_MAP.values());
USER_MAP.clear();
return CommonResult.success("删除所有用户成功", users);
}
}
package com.rtxtitanv.service;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.Order;
import java.util.List;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.service.OrderService
* @description OrderService
* @date 2021/6/8 17:18
*/
public interface OrderService {
/**
* 保存订单
*
* @param order 订单参数
* @return CommonResult<Order>
*/
CommonResult<Order> saveOrder(Order order);
/**
* 查询所有订单
*
* @return CommonResult<List<Order>>
*/
CommonResult<List<Order>> findOrderAll();
/**
* 根据id更新订单
*
* @param order 订单参数
* @return CommonResult<Order>
*/
CommonResult<Order> updateOrderById(Order order);
/**
* 根据id删除订单
*
* @param id 订单id
* @return CommonResult<Order>
*/
CommonResult<Order> deleteOrderById(Long id);
}
package com.rtxtitanv.service.impl;
import com.rtxtitanv.exception.InvalidParameterException;
import com.rtxtitanv.exception.NotFoundException;
import com.rtxtitanv.model.CommonResult;
import com.rtxtitanv.model.Order;
import com.rtxtitanv.service.OrderService;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.service.impl.OrderServiceImpl
* @description OrderService实现类
* @date 2021/6/8 17:18
*/
@Service
public class OrderServiceImpl implements OrderService {
/**
* 创建线程安全的Map,模拟订单信息的存储
*/
private static final Map<Long, Order> ORDER_MAP = Collections.synchronizedMap(new HashMap<>());
@Override
public CommonResult<Order> saveOrder(Order order) {
if (order.getId() <= 0) {
throw new InvalidParameterException("无效参数");
}
ORDER_MAP.put(order.getId(), order);
return CommonResult.success("保存订单成功", order);
}
@Override
public CommonResult<List<Order>> findOrderAll() {
return CommonResult.success("查询所有订单成功", new ArrayList<>(ORDER_MAP.values()));
}
@Override
public CommonResult<Order> updateOrderById(Order order) {
if (order.getId() <= 0) {
throw new InvalidParameterException("无效参数");
}
if (ORDER_MAP.get(order.getId()) == null) {
throw new NotFoundException("订单不存在");
}
order = ORDER_MAP.get(order.getId()).setOrderNumber(order.getOrderNumber())
.setOrderDescription(order.getOrderDescription()).setUserId(order.getUserId());
return CommonResult.success("根据id更新订单成功", order);
}
@Override
public CommonResult<Order> deleteOrderById(Long id) {
if (id <= 0) {
throw new InvalidParameterException("无效参数");
}
if (ORDER_MAP.get(id) == null) {
throw new NotFoundException("订单不存在");
}
return CommonResult.success("根据id删除订单成功", ORDER_MAP.remove(id));
}
}
六、全局异常处理
自定义异常类:
package com.rtxtitanv.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.exception.InvalidParameterException
* @description 自定义异常类,无效参数异常
* @date 2021/6/8 18:56
*/
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@Data
public class InvalidParameterException extends RuntimeException implements Serializable {
private static final long serialVersionUID = 1987968660448772948L;
private String message;
}
package com.rtxtitanv.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.exception.NotFoundException
* @description 自定义异常类,数据不存在的异常
* @date 2021/6/8 18:56
*/
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@Data
public class NotFoundException extends RuntimeException implements Serializable {
private static final long serialVersionUID = -7962596135697516276L;
private String message;
}
全局异常处理类:
package com.rtxtitanv.handler;
import com.rtxtitanv.exception.InvalidParameterException;
import com.rtxtitanv.exception.NotFoundException;
import com.rtxtitanv.model.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author rtxtitanv
* @version 1.0.0
* @name com.rtxtitanv.handler.GlobalExceptionHandler
* @description 全局异常处理类
* @date 2021/6/8 18:56
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(InvalidParameterException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public CommonResult<Object> invalidParameterException(InvalidParameterException e) {
String message = e.getMessage();
LOGGER.error("异常信息:" + message, e);
return CommonResult.invalidParameter(message);
}
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public CommonResult<Object> notFoundException(NotFoundException e) {
String message = e.getMessage();
LOGGER.error("异常信息:" + message, e);
return CommonResult.notFound(message);
}
}
七、运行项目查看文档
启动SpringBoot项目,访问Swagger-UI的地址http://localhost:8080/swagger-ui/查看接口文档:
切换到user分组:
切换到order分组:
创建订单接口如下:
创建订单接口的响应信息如下:
更新订单接口如下:
订单管理API的Schema:
八、测试接口
可以在API文档中进行接口测试。首先测试创建订单接口以保存订单,与Swagger2不同,在配置了JWT安全认证之后,页面右侧多了个Authorize按钮,点击该按钮,输入Token认证后,每次请求都会将该Token加到Authorization请求头中来访问后台资源:
点击Try it out按钮,输入参数后点击Execute:
测试结果如下,可见保存成功:
在进行查询测试前再保存2个数据,然后测试查询所有订单:
测试根据id更新订单接口:
测试根据id删除订单接口:
下面测试抛出自定义异常的情况,测试根据id删除订单接口,输入一个无效id:
测试根据id更新订单接口,更新一个不存在的订单:
九、引入knife4j
Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。前身是swagger-bootstrap-ui。
首先引入依赖:
<!-- knife4j 起步依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
注意:knife4j的版本需要根据引入的springfox版本而定。如果底层依赖的springfox框架版本是
2.9.2
,knife4j的版本使用2.02.0.5。如果底层springfox框架版本升级至`2.10.5`,OpenAPI规范是v2,knife4j的版本使用2.0.6。如果底层依赖springfox框架版本升级至3.0.3
,OpenAPI规范是v3,knife4j的版本使用3.0~。
重启SpringBoot项目,访问knife4j的地址http://localhost:8080/doc.html查看接口文档:
代码示例
- Github:https://github.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-swagger3
- Gitee:https://gitee.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-swagger3
最后
以上就是乐观红酒为你收集整理的SpringBoot2.x 集成 Swagger3一、引入依赖二、编写配置类三、创建实体类四、Controller层五、Service层六、全局异常处理七、运行项目查看文档八、测试接口九、引入knife4j的全部内容,希望文章能够帮你解决SpringBoot2.x 集成 Swagger3一、引入依赖二、编写配置类三、创建实体类四、Controller层五、Service层六、全局异常处理七、运行项目查看文档八、测试接口九、引入knife4j所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复