Spring Boot整合Knife4j案例

wen java案例 3

本文目录导读:

Spring Boot整合Knife4j案例

  1. 项目基础配置
  2. 核心配置类
  3. 实体类定义
  4. Controller层实现
  5. Service层实现
  6. 全局异常处理
  7. 启动类
  8. 高级特性配置
  9. 使用示例
  10. 最佳实践建议

我来为您提供一个完整的Spring Boot整合Knife4j的案例,包括基础配置、高级特性和最佳实践。

项目基础配置

1 创建Spring Boot项目

pom.xml 核心依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.14</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>knife4j-demo</artifactId>
    <version>1.0.0</version>
    <name>knife4j-demo</name>
    <description>Spring Boot整合Knife4j示例</description>
    <properties>
        <java.version>1.8</java.version>
        <knife4j.version>4.1.0</knife4j.version>
    </properties>
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Knife4j -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>
        <!-- Lombok 简化代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 参数校验 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2 配置文件

application.yml

server:
  port: 8080
spring:
  application:
    name: knife4j-demo
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
# Knife4j配置
knife4j:
  enable: true
  basic:
    enable: false  # 是否开启Basic认证
    username: admin
    password: admin123
  setting:
    language: zh_cn  # 语言
    enable-footer: true
    enable-footer-custom: true
    footer-custom-content: Apache License 2.0
    enable-open-api: true
    enable-group: true
    enable-dynamic-parameter: true
    enable-request-cache: true
    enable-version: true
    enable-debug: true
# 自定义配置
api: 用户管理系统API
  description: 这是一个示例API文档
  version: 1.0.0
  contact:
    name: 开发团队
    email: dev@example.com
    url: https://example.com
  base-package: com.example.knife4jdemo.controller
  terms-of-service-url: https://example.com/terms
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html

核心配置类

1 基础配置类

package com.example.knife4jdemo.config;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Value;
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.*;
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;
@Configuration
@EnableSwagger2
public class Knife4jConfig {
    @Value("${api.title}")
    private String title;
    @Value("${api.description}")
    private String description;
    @Value("${api.version}")
    private String version;
    @Value("${api.base-package}")
    private String basePackage;
    @Value("${api.contact.name}")
    private String contactName;
    @Value("${api.contact.email}")
    private String contactEmail;
    @Value("${api.contact.url}")
    private String contactUrl;
    @Value("${api.terms-of-service-url}")
    private String termsOfServiceUrl;
    @Value("${api.license.name}")
    private String licenseName;
    @Value("${api.license.url}")
    private String licenseUrl;
    /**
     * API文档 - 用户接口
     */
    @Bean
    public Docket userApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("用户接口")
                .apiInfo(userApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.regex("/api/user/.*"))
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }
    /**
     * API文档 - 系统接口
     */
    @Bean
    public Docket systemApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("系统接口")
                .apiInfo(systemApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.regex("/api/system/.*"))
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }
    /**
     * API文档 - 全部接口
     */
    @Bean
    public Docket allApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("全部接口")
                .apiInfo(apiInfo(title, description, version))
                .select()
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }
    private ApiInfo userApiInfo() {
        return apiInfo("用户管理API", "用户相关的接口文档", "1.0.0");
    }
    private ApiInfo systemApiInfo() {
        return apiInfo("系统管理API", "系统相关的接口文档", "1.0.0");
    }
    private ApiInfo apiInfo(String title, String description, String version) {
        return new ApiInfoBuilder()
                .title(title)
                .description(description)
                .version(version)
                .termsOfServiceUrl(termsOfServiceUrl)
                .contact(new Contact(contactName, contactUrl, contactEmail))
                .license(licenseName)
                .licenseUrl(licenseUrl)
                .build();
    }
    /**
     * 安全认证配置
     */
    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> securitySchemes = new ArrayList<>();
        securitySchemes.add(new ApiKey("Authorization", "Authorization", "header"));
        return securitySchemes;
    }
    /**
     * 安全上下文
     */
    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .build());
        return securityContexts;
    }
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferences;
    }
}

2 全局响应封装

package com.example.knife4jdemo.common;
import lombok.Data;
import java.io.Serializable;
@Data
public class Result<T> implements Serializable {
    private Integer code;
    private String message;
    private T data;
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("success");
        result.setData(data);
        return result;
    }
    public static <T> Result<T> success(String message, T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage(message);
        result.setData(data);
        return result;
    }
    public static <T> Result<T> error(String message) {
        Result<T> result = new Result<>();
        result.setCode(500);
        result.setMessage(message);
        return result;
    }
    public static <T> Result<T> error(Integer code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
}

3 通用分页结果

package com.example.knife4jdemo.common;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class PageResult<T> implements Serializable {
    private List<T> items;
    private long total;
    private int page;
    private int size;
    private int totalPages;
    public static <T> PageResult<T> build(List<T> items, long total, int page, int size) {
        PageResult<T> result = new PageResult<>();
        result.setItems(items);
        result.setTotal(total);
        result.setPage(page);
        result.setSize(size);
        result.setTotalPages((int) Math.ceil((double) total / size));
        return result;
    }
}

实体类定义

1 用户实体

package com.example.knife4jdemo.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "用户实体", description = "用户信息")
public class User implements Serializable {
    @ApiModelProperty(value = "用户ID", example = "1")
    private Long id;
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
    @ApiModelProperty(value = "用户名", required = true, example = "zhangsan")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
    @ApiModelProperty(value = "密码", required = true, example = "123456")
    private String password;
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    @ApiModelProperty(value = "邮箱", example = "zhangsan@example.com")
    private String email;
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    @ApiModelProperty(value = "手机号", example = "13800138000")
    private String phone;
    @Min(value = 1, message = "年龄不能小于1")
    @Max(value = 150, message = "年龄不能大于150")
    @ApiModelProperty(value = "年龄", example = "25")
    private Integer age;
    @ApiModelProperty(value = "性别", example = "男")
    private String gender;
    @ApiModelProperty(value = "状态", example = "1", notes = "1:启用 0:禁用")
    private Integer status;
    @ApiModelProperty(value = "创建时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "更新时间")
    private LocalDateTime updateTime;
}

2 DTO类

package com.example.knife4jdemo.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.*;
import java.io.Serializable;
@Data
@ApiModel(value = "用户创建请求", description = "创建用户所需的参数")
public class UserCreateRequest implements Serializable {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
    @ApiModelProperty(value = "用户名", required = true, example = "lisi")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
    @ApiModelProperty(value = "密码", required = true, example = "123456")
    private String password;
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    @ApiModelProperty(value = "邮箱", example = "lisi@example.com")
    private String email;
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    @ApiModelProperty(value = "手机号", example = "13900139000")
    private String phone;
    @Min(value = 1, message = "年龄不能小于1")
    @Max(value = 150, message = "年龄不能大于150")
    @ApiModelProperty(value = "年龄", example = "26")
    private Integer age;
    @ApiModelProperty(value = "性别", example = "女")
    private String gender;
}
package com.example.knife4jdemo.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "用户查询条件", description = "用户列表查询参数")
public class UserQueryRequest implements Serializable {
    @ApiModelProperty(value = "当前页码", example = "1")
    private Integer page = 1;
    @ApiModelProperty(value = "每页大小", example = "10")
    private Integer size = 10;
    @ApiModelProperty(value = "用户名关键字", example = "张")
    private String username;
    @ApiModelProperty(value = "邮箱", example = "example@example.com")
    private String email;
    @ApiModelProperty(value = "状态", example = "1")
    private Integer status;
    @ApiModelProperty(value = "创建时间开始", example = "2023-01-01 00:00:00")
    private String createTimeStart;
    @ApiModelProperty(value = "创建时间结束", example = "2023-12-31 23:59:59")
    private String createTimeEnd;
}

Controller层实现

1 用户控制器

package com.example.knife4jdemo.controller;
import com.example.knife4jdemo.common.PageResult;
import com.example.knife4jdemo.common.Result;
import com.example.knife4jdemo.dto.UserCreateRequest;
import com.example.knife4jdemo.dto.UserQueryRequest;
import com.example.knife4jdemo.entity.User;
import com.example.knife4jdemo.service.UserService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.List;
@Api(tags = "用户管理", description = "用户相关接口")
@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
@Validated
public class UserController {
    private final UserService userService;
    @ApiOperation(value = "创建用户", notes = "创建一个新用户")
    @ApiResponses({
        @ApiResponse(code = 200, message = "创建成功"),
        @ApiResponse(code = 400, message = "参数错误"),
        @ApiResponse(code = 500, message = "服务器内部错误")
    })
    @PostMapping("/create")
    @ResponseStatus(HttpStatus.CREATED)
    public Result<User> createUser(@Valid @RequestBody UserCreateRequest request) {
        return Result.success("创建用户成功", userService.createUser(request));
    }
    @ApiOperation(value = "更新用户", notes = "根据用户ID更新用户信息")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "id", value = "用户ID", required = true, 
                         dataType = "Long", paramType = "path", example = "1"),
        @ApiImplicitParam(name = "user", value = "用户信息", required = true, 
                         dataType = "User", paramType = "body")
    })
    @PutMapping("/update/{id}")
    public Result<User> updateUser(
            @PathVariable @Min(value = 1, message = "用户ID必须大于0") Long id,
            @Valid @RequestBody User user) {
        return Result.success("更新用户成功", userService.updateUser(id, user));
    }
    @ApiOperation(value = "删除用户", notes = "根据用户ID删除用户")
    @DeleteMapping("/delete/{id}")
    public Result<Void> deleteUser(@PathVariable("id") Long id) {
        userService.deleteUser(id);
        return Result.success("删除用户成功", null);
    }
    @ApiOperation(value = "获取用户详情", notes = "根据用户ID获取用户详细信息")
    @GetMapping("/get/{id}")
    public Result<User> getUserById(@PathVariable("id") Long id) {
        return Result.success(userService.getUserById(id));
    }
    @ApiOperation(value = "分页查询用户", notes = "分页条件查询用户列表")
    @PostMapping("/page")
    public Result<PageResult<User>> pageUsers(@RequestBody UserQueryRequest query) {
        return Result.success(userService.pageUsers(query));
    }
    @ApiOperation(value = "获取所有用户", notes = "获取系统中所有用户列表")
    @GetMapping("/list")
    public Result<List<User>> getAllUsers() {
        return Result.success(userService.getAllUsers());
    }
    @ApiOperation(value = "批量删除用户", notes = "根据用户ID列表批量删除用户")
    @DeleteMapping("/batch/delete")
    public Result<Void> batchDeleteUsers(@RequestBody List<Long> ids) {
        userService.batchDeleteUsers(ids);
        return Result.success("批量删除成功", null);
    }
    @ApiOperation(value = "导出用户数据", notes = "导出用户信息到CSV文件")
    @GetMapping("/export")
    public void exportUsers() {
        userService.exportUsers();
    }
}

2 系统控制器

package com.example.knife4jdemo.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Api(tags = "系统管理", description = "系统相关接口")
@RestController
@RequestMapping("/api/system")
@Slf4j
public class SystemController {
    @ApiOperation(value = "获取系统信息", notes = "获取系统运行状态和信息")
    @GetMapping("/info")
    public Map<String, Object> getSystemInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("appName", "knife4j-demo");
        info.put("version", "1.0.0");
        info.put("javaVersion", System.getProperty("java.version"));
        info.put("osName", System.getProperty("os.name"));
        return info;
    }
    @ApiOperation(value = "健康检查", notes = "服务健康状态检查")
    @GetMapping("/health")
    public Map<String, String> healthCheck() {
        Map<String, String> health = new HashMap<>();
        health.put("status", "UP");
        health.put("message", "服务运行正常");
        return health;
    }
    @ApiOperation(value = "执行SQL", notes = "执行指定的SQL语句(仅限查询)")
    @PostMapping("/sql/execute")
    public Map<String, Object> executeSql(
            @ApiParam(value = "SQL语句", required = true, example = "SELECT * FROM user") 
            @RequestParam String sql) {
        log.info("执行SQL: {}", sql);
        Map<String, Object> result = new HashMap<>();
        result.put("sql", sql);
        result.put("success", true);
        result.put("message", "SQL执行成功");
        return result;
    }
}

Service层实现

package com.example.knife4jdemo.service;
import com.example.knife4jdemo.common.PageResult;
import com.example.knife4jdemo.dto.UserCreateRequest;
import com.example.knife4jdemo.dto.UserQueryRequest;
import com.example.knife4jdemo.entity.User;
import com.example.knife4jdemo.exception.BusinessException;
import java.util.List;
public interface UserService {
    User createUser(UserCreateRequest request);
    User updateUser(Long id, User user);
    void deleteUser(Long id);
    User getUserById(Long id);
    PageResult<User> pageUsers(UserQueryRequest query);
    List<User> getAllUsers();
    void batchDeleteUsers(List<Long> ids);
    void exportUsers();
}
package com.example.knife4jdemo.service.impl;
import com.example.knife4jdemo.common.PageResult;
import com.example.knife4jdemo.dto.UserCreateRequest;
import com.example.knife4jdemo.dto.UserQueryRequest;
import com.example.knife4jdemo.entity.User;
import com.example.knife4jdemo.exception.BusinessException;
import com.example.knife4jdemo.service.UserService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserServiceImpl implements UserService {
    // 模拟数据库存储
    private final List<User> userStore = new ArrayList<>();
    @Override
    public User createUser(UserCreateRequest request) {
        User user = new User();
        user.setId(System.currentTimeMillis());
        user.setUsername(request.getUsername());
        user.setPassword(request.getPassword());
        user.setEmail(request.getEmail());
        user.setPhone(request.getPhone());
        user.setAge(request.getAge());
        user.setGender(request.getGender());
        user.setStatus(1);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        userStore.add(user);
        return user;
    }
    @Override
    public User updateUser(Long id, User user) {
        User existingUser = getUserById(id);
        existingUser.setUsername(user.getUsername());
        existingUser.setEmail(user.getEmail());
        existingUser.setPhone(user.getPhone());
        existingUser.setAge(user.getAge());
        existingUser.setGender(user.getGender());
        existingUser.setStatus(user.getStatus());
        existingUser.setUpdateTime(LocalDateTime.now());
        return existingUser;
    }
    @Override
    public void deleteUser(Long id) {
        boolean removed = userStore.removeIf(user -> user.getId().equals(id));
        if (!removed) {
            throw new BusinessException(404, "用户不存在");
        }
    }
    @Override
    public User getUserById(Long id) {
        return userStore.stream()
                .filter(user -> user.getId().equals(id))
                .findFirst()
                .orElseThrow(() -> new BusinessException(404, "用户不存在"));
    }
    @Override
    public PageResult<User> pageUsers(UserQueryRequest query) {
        List<User> users = userStore.stream()
                .filter(user -> query.getUsername() == null || 
                        user.getUsername().contains(query.getUsername()))
                .filter(user -> query.getEmail() == null || 
                        user.getEmail().equals(query.getEmail()))
                .filter(user -> query.getStatus() == null || 
                        user.getStatus().equals(query.getStatus()))
                .collect(Collectors.toList());
        int start = (query.getPage() - 1) * query.getSize();
        int end = Math.min(start + query.getSize(), users.size());
        List<User> pageItems = start >= users.size() ? 
                new ArrayList<>() : users.subList(start, end);
        return PageResult.build(pageItems, users.size(), query.getPage(), query.getSize());
    }
    @Override
    public List<User> getAllUsers() {
        return new ArrayList<>(userStore);
    }
    @Override
    public void batchDeleteUsers(List<Long> ids) {
        userStore.removeIf(user -> ids.contains(user.getId()));
    }
    @Override
    public void exportUsers() {
        // 实现导出逻辑
        System.out.println("导出用户数据...");
    }
}

全局异常处理

package com.example.knife4jdemo.exception;
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
    private final Integer code;
    public BusinessException(String message) {
        super(message);
        this.code = 500;
    }
    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}
package com.example.knife4jdemo.handler;
import com.example.knife4jdemo.common.Result;
import com.example.knife4jdemo.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.error("业务异常: {}", e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        return Result.error(400, message);
    }
    @ExceptionHandler(BindException.class)
    public Result<Void> handleBindException(BindException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        return Result.error(400, message);
    }
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Void> handleConstraintViolation(ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
        return Result.error(400, message);
    }
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return Result.error(500, "系统内部错误,请联系管理员");
    }
}

启动类

package com.example.knife4jdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Knife4jDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(Knife4jDemoApplication.class, args);
        System.out.println("Knife4j文档地址: http://localhost:8080/doc.html");
    }
}

高级特性配置

1 接口排序配置

@Configuration
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("所有接口")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.knife4jdemo"))
                .paths(PathSelectors.any())
                .build()
                .tags(new Tag("用户管理", "用户相关接口,按优先级排序"))
                .useDefaultResponseMessages(false)
                .globalRequestParameters(globalRequestParameters());
    }
    // 全局请求参数
    private List<RequestParameter> globalRequestParameters() {
        List<RequestParameter> parameters = new ArrayList<>();
        parameters.add(new RequestParameterBuilder()
                .name("X-Trace-Id")
                .description("追踪ID")
                .in(ParameterType.HEADER)
                .required(false)
                .build());
        return parameters;
    }
}

2 忽略接口配置

@Configuration
public class IgnoreConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("核心接口")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.knife4jdemo"))
                .paths(PathSelectors.ant("/api/user/**")
                        .or(PathSelectors.ant("/api/system/**")))
                .build();
    }
}

3 Swagger2 API配置

@Configuration
public class SwaggerConfig {
    // 对API分组配置
    @Bean
    public Docket group1() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("分组1")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.ant("/api/**"))
                .build();
    }
    @Bean
    public Docket group2() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("分组2")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.ant("/admin/**"))
                .build();
    }
}

使用示例

1 访问文档

启动应用后访问:

  • Knife4j界面:http://localhost:8080/doc.html
  • Swagger2文档:http://localhost:8080/swagger-ui/index.html
  • OpenAPI3文档:http://localhost:8080/v3/api-docs

2 常见注解说明

// Controller类级别注解
@Api(tags = "用户管理", description = "用户相关接口")
// 操作方法注解
@ApiOperation(value = "创建用户", notes = "创建用户的详细说明")
// 参数注解
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
// 实体类注解
@ApiModel(value = "用户实体", description = "用户信息")
// 属性注解
@ApiModelProperty(value = "用户ID", example = "1")
// 响应注解
@ApiResponse(code = 200, message = "请求成功")
// 全局响应
@ApiResponses({
    @ApiResponse(code = 200, message = "成功"),
    @ApiResponse(code = 400, message = "参数错误")
})

3 生产环境配置

# application-prod.yml
knife4j:
  enable: false  # 生产环境关闭
  production: true  # 只读模式,隐藏调试功能
@Configuration
@Profile("dev")  // 只在开发环境启用
public class SwaggerDevConfig {
    // 配置代码
}

最佳实践建议

  1. 接口分组管理:根据业务模块合理分组
  2. 版本控制:使用 @ApiVersion 管理API版本
  3. 统一响应格式:所有接口返回统一格式的 Result
  4. 参数校验:使用 JSR-303 注解进行参数校验
  5. 错误码管理:定义统一错误码规范
  6. 文档更新:保持API注释与代码同步更新
  7. 安全限制:生产环境关闭文档或添加访问认证
  8. 性能优化:避免在文档中包含敏感信息

这个案例提供了完整的Spring Boot整合Knife4j的方案,您可以基于此进行扩展和自定义配置。

抱歉,评论功能暂时关闭!