一、函数式路由的崛起背景
在Spring Boot的传统开发模式中,我们习惯使用@RestController和@RequestMapping等注解来构建Web接口。这种方式简洁明了,但随着项目规模扩大,Controller类可能变得臃肿,注解配置也变得复杂。
函数式编程模型为Spring Web开发带来了全新的思路。它通过HandlerFunction和RouterFunction这两个核心概念,以声明式、函数式的方式定义路由,代码更加简洁、直观,特别适合构建轻量级、响应式的Web服务。
二、核心概念解析
2.1 HandlerFunction:请求处理的核心
HandlerFunction是一个函数接口,接收ServerRequest并返回ServerResponse。它类似于传统Controller中带有@RequestMapping注解的方法体。
bash
// 函数式接口定义
@FunctionalInterface
public interface HandlerFunction<T extends ServerResponse> {
T handle(ServerRequest request) throws Exception;
}
2.2 RouterFunction:路由定义器
RouterFunction用于将HTTP请求路由到对应的HandlerFunction。Spring提供了RouterFunctions工具类来简化路由定义。
三、实战:基于Servlet的阻塞式路由
3.1 定义HandlerFunction
bash
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.*;
import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.ServerResponse.*;
@Component
public class PersonHandler {
private final PersonRepository personRepository;
public PersonHandler(PersonRepository personRepository) {
this.personRepository = personRepository;
}
// 查询所有人
public ServerResponse listPeople(ServerRequest request) {
List<Person> people = personRepository.findAll();
return ok()
.contentType(APPLICATION_JSON)
.body(people);
}
// 创建人员
public ServerResponse createPerson(ServerRequest request) throws Exception {
Person person = request.body(Person.class);
personRepository.save(person);
return ok().build();
}
// 根据ID查询
public ServerResponse getPerson(ServerRequest request) {
Long id = Long.valueOf(request.pathVariable("id"));
Person person = personRepository.findById(id).orElse(null);
if (person != null) {
return ok()
.contentType(APPLICATION_JSON)
.body(person);
} else {
return notFound().build();
}
}
}
3.2 定义RouterFunction
bash
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.function.*;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.RequestPredicates.accept;
@Configuration
public class RouterConfig {
@Bean
public RouterFunction<ServerResponse> personRouter(PersonHandler handler) {
return RouterFunctions.route()
.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
.GET("/person", accept(APPLICATION_JSON), handler::listPeople)
.POST("/person", handler::createPerson)
.build();
}
}
四、实战:基于WebFlux的响应式路由
4.1 添加依赖
bash
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
4.2 响应式HandlerFunction
bash
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
@Component
public class UserHandler {
public Mono<ServerResponse> getById(ServerRequest request) {
String id = request.pathVariable("id");
return ServerResponse.ok()
.bodyValue("Received ID: " + id);
}
public Mono<ServerResponse> getByParam(ServerRequest request) {
String name = request.queryParam("name")
.orElse("Guest");
return ServerResponse.ok()
.bodyValue("Hello, " + name);
}
public Mono<ServerResponse> createUser(ServerRequest request) {
return request.bodyToMono(User.class)
.flatMap(user ->
ServerResponse.ok()
.bodyValue("User created: " + user.getName())
);
}
}
4.3 响应式路由配置
bash
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.*;
@Configuration
public class WebFluxRouterConfig {
@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler) {
return RouterFunctions.route()
.GET("/user/{id}", handler::getById)
.GET("/user/param", handler::getByParam)
.POST("/user", handler::createUser)
.build();
}
}
五、进阶特性
5.1 参数验证
bash
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Component
public class ValidatedPersonHandler {
private final Validator validator;
public Mono<ServerResponse> createPerson(ServerRequest request) {
return request.bodyToMono(Person.class)
.doOnNext(this::validate)
.flatMap(person ->
ServerResponse.ok()
.bodyValue("Validated: " + person.getName())
);
}
private void validate(Person person) {
Errors errors = new BeanPropertyBindingResult(
person, "person");
validator.validate(person, errors);
if (errors.hasErrors()) {
throw new ServerWebInputException(
"Validation failed: " + errors.toString());
}
}
}
5.2 嵌套路由
bash
@Bean
public RouterFunction<ServerResponse> nestedRoutes(PersonHandler handler) {
return RouterFunctions.route()
.path("/api", builder -> builder
.path("/v1", v1Builder -> v1Builder
.path("/person", personBuilder -> personBuilder
.GET("/{id}", handler::getPerson)
.GET("/", handler::listPeople)
.POST("/", handler::createPerson)
)
)
)
.build();
}
5.3 路由过滤
bash
@Bean
public RouterFunction<ServerResponse> filteredRoutes(PersonHandler handler) {
return RouterFunctions.route()
.before(request -> {
// 前置处理:添加请求头
System.out.println("Before handling: " + request.uri());
return ServerRequest.from(request)
.header("X-Request-Timestamp",
String.valueOf(System.currentTimeMillis()))
.build();
})
.GET("/person/{id}", handler::getPerson)
.after((request, response) -> {
// 后置处理:记录响应
System.out.println("After handling: " + response.statusCode());
return response;
})
.filter((request, next) -> {
// 过滤器:身份验证
if (!request.headers().header("Authorization").isEmpty()) {
return next.handle(request);
} else {
return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
}
})
.build();
}
5.4 静态资源重定向
bash
@Bean
public RouterFunction<ServerResponse> spaRoutes() {
// 匹配需要重定向到前端的请求
RequestPredicate spaPredicate = RequestPredicates.path("/api/**")
.or(RequestPredicates.path("/error"))
.negate();
// 重定向到前端资源
return RouterFunctions.route()
.resource(spaPredicate,
new ClassPathResource("static/index.html"))
.build();
}
六、与传统Controller对比
| 特性 | 传统注解Controller | 函数式路由 |
|---|---|---|
| 代码风格 | 面向对象 | 函数式编程 |
| 路由配置 | 注解驱动 | 代码声明式 |
| 灵活性 | 中等 | 高 |
| 学习曲线 | 平缓 | 较陡 |
| 测试便利性 | 中等 | 高 |
| 适用场景 | 传统Web应用 | 微服务、API网关 |
七、最佳实践建议
渐进式迁移:对于现有项目,可以先在新增接口中使用函数式路由,逐步替换
统一风格:在团队中保持一致性,要么全部使用注解,要么全部使用函数式
合理分层:将业务逻辑与路由逻辑分离,保持HandlerFunction的简洁性
充分利用组合:利用函数式编程的组合特性,创建可复用的路由组件
文档注释:由于缺乏注解的元数据,需要添加详细的文档注释
八、总结
Spring Boot的函数式路由为开发者提供了另一种构建Web应用的选择。它通过HandlerFunction和RouterFunction这两个核心抽象,实现了更加灵活、声明式的路由定义方式。虽然学习成本相对较高,但对于需要构建轻量级、高性能、响应式服务的场景,函数式路由无疑是一个强大的工具。
在选择技术方案时,应根据项目需求、团队技术栈和长期维护成本综合考虑。函数式路由特别适合:
构建API网关
微服务架构中的轻量级服务
需要高度可测试性的项目
对性能有严格要求的应用
无论选择哪种方式,Spring Boot都为我们提供了强大而灵活的工具,让Web开发变得更加高效和愉快。
实战演练
bash
<!--web 模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
换成
bash
<!--webflux 模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
大家熟知的 controller
bash
package com.cqcloud.platform.controller;
import com.cqcloud.platform.common.log.annotation.SysLog;
import com.cqcloud.platform.common.matter.utils.Result;
import com.cqcloud.platform.common.security.annotation.HasPermission;
import com.cqcloud.platform.entity.SysDept;
import com.cqcloud.platform.service.SysDeptService;
import com.cqcloud.platform.vo.SysTreeVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 系统基础信息--部门管理模块
*
* @author weimeilayer@gmail.com ✨
* @date 💓💕 2023年5月20日 🐬🐇 💓💕
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/dept")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
@Tag(description = "系统基础信息--部门管理模块操作接口", name = "系统基础信息--部门管理模块操作接口")
public class SysDeptController {
private final SysDeptService sysDeptService;
/**
* 通过ID查询
* @param id ID
* @return SysDept
*/
@GetMapping("/{id}")
@Operation(summary = "通过ID查询", description = "通过ID查询")
public Result<SysDept> getById(@PathVariable String id) {
return Result.ok(sysDeptService.getById(id));
}
/**
* 添加部门
* @param sysDept 实体
* @return 是否成功
*/
@SysLog("添加部门")
@PostMapping
@HasPermission("sys_dept_add")
@Operation(summary = "添加部门", description = "添加部门")
public Result<Boolean> save(@Valid @RequestBody SysDept sysDept) {
return Result.ok(sysDeptService.save(sysDept));
}
/**
* 编辑部门
* @param sysDept 实体
* @return 是否成功
*/
@SysLog("编辑部门")
@PutMapping
@HasPermission("sys_dept_edit")
@Operation(summary = "编辑部门", description = "编辑部门")
public Result<Boolean> update(@Valid @RequestBody SysDept sysDept) {
return Result.ok(sysDeptService.updateById(sysDept));
}
/**
* 删除部门
* @param id 部门ID
* @return 是否成功
*/
@SysLog("删除部门")
@DeleteMapping("/{id}")
@HasPermission("sys_dept_del")
@Operation(summary = "删除部门", description = "删除部门")
public Result<?> removeById(@PathVariable String id) {
return sysDeptService.removeDeptById(id) ? Result.success("删除成功") : Result.failed("删除失败");
}
/**
* 获取部门的本级及所有下级部门列表
* @return 部门的本级及所有下级部门列表
*/
@GetMapping(value = "/getDescendantList/{deptId}")
@Operation(summary = "获取部门的本级及所有下级部门列表", description = "获取部门的本级及所有下级部门列表")
public Result<List<SysDept>> getDescendantList(@PathVariable String deptId) {
return Result.ok(sysDeptService.listDescendant(deptId));
}
/**
* 获取部门树集合
* @param parentId 父级ID
* @param lazyLoading 是否懒加载
* @return 部门树
*/
@GetMapping("/getDeptTree")
@Parameters({ @Parameter(name = "parentId", description = "父级编号", example = "-1"),
@Parameter(name = "lazyLoading", description = "是否懒加载", required = true, example = "true") })
@Operation(summary = "获取部门树集合", description = "获取部门树集合")
public Result<List<SysDept>> getDeptTree(String parentId, Boolean lazyLoading) {
return Result.ok(sysDeptService.getDeptTree(parentId, lazyLoading));
}
/**
* 采用栈方式获取部门树
* @param parentId 父级ID
* @param lazyLoading 是否懒加载
* @return 部门树
*/
@GetMapping("/getTree")
@Parameters({ @Parameter(name = "parentId", description = "父级编号", example = "-1"),
@Parameter(name = "lazyLoading", description = "是否懒加载", required = true, example = "true") })
@Operation(summary = "采用栈方式获取部门树", description = "采用栈方式获取部门树")
public Result<List<SysTreeVo>> getTree(String parentId, Boolean lazyLoading) {
return Result.ok(sysDeptService.getTree(parentId, lazyLoading));
}
}
转换后的
bash
package com.cqcloud.platform.config;
import com.cqcloud.platform.filter.OperationLogFilter;
import com.cqcloud.platform.handler.PermissionHandler;
import com.cqcloud.platform.handler.SysDeptHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.RequestPredicates.*;
import static org.springframework.web.servlet.function.RouterFunctions.route;
/**
* 部门管理模块路由配置
* @author weimeilayer@gmail.com ✨
* @date 💓💕 2023年5月20日 🐬🐇 💓💕
*/
@Configuration
@RequiredArgsConstructor
public class CompleteDeptRouterConfig {
private final SysDeptHandler handler;
private final PermissionHandler permissionHandler;
private final OperationLogFilter logFilter;
@Bean
public RouterFunction<ServerResponse> deptRoutes() {
return route()
// 查询接口(只需要日志)
.GET("/dept/{id}", accept(APPLICATION_JSON), handler::getById)
.filter(logFilter.logOperation("查询部门详情"))
.GET("/dept/getDescendantList/{deptId}", accept(APPLICATION_JSON), handler::getDescendantList)
.filter(logFilter.logOperation("获取下级部门列表"))
.GET("/dept/getDeptTree", accept(APPLICATION_JSON), handler::getDeptTree)
.filter(logFilter.logOperation("获取部门树"))
.GET("/dept/getTree", accept(APPLICATION_JSON), handler::getTree)
.filter(logFilter.logOperation("获取部门树(栈方式)"))
// 添加部门(权限+日志)
.POST("/dept", accept(APPLICATION_JSON), handler::save)
.filter(permissionHandler.requirePermission("sys_dept_add"))
.filter(logFilter.logOperation("添加部门"))
// 编辑部门(权限+日志)
.PUT("/dept", accept(APPLICATION_JSON), handler::update)
.filter(permissionHandler.requirePermission("sys_dept_edit"))
.filter(logFilter.logOperation("编辑部门"))
// 删除部门(权限+日志)
.DELETE("/dept/{id}", handler::removeById)
.filter(permissionHandler.requirePermission("sys_dept_del"))
.filter(logFilter.logOperation("删除部门"))
.build();
}
}
bash
package com.cqcloud.platform.filter;
import com.cqcloud.platform.common.log.annotation.SysLog;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.HandlerFilterFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
/**
* 操作日志过滤器
* @author weimeilayer@gmail.com ✨
* @date 💓💕 2023年5月20日 🐬🐇 💓💕
*/
@Component
public class OperationLogFilter {
/**
* 创建日志过滤器
* @param operation 操作描述
*/
public HandlerFilterFunction<ServerResponse, ServerResponse> logOperation(String operation) {
return (request, next) -> {
// 记录操作前
logBefore(operation, request);
try {
ServerResponse response = next.handle(request);
// 记录操作成功
logSuccess(operation, request, response);
return response;
} catch (Exception e) {
// 记录操作失败
logError(operation, request, e);
throw e;
}
};
}
/**
* 从@SysLog注解值创建过滤器
*/
public HandlerFilterFunction<ServerResponse, ServerResponse> fromSysLog(SysLog sysLog) {
return (request, next) -> {
System.out.println("[操作日志] " + sysLog.value() + ": " + request.method() + " " + request.path());
return next.handle(request);
};
}
private void logBefore(String operation, ServerRequest request) {
System.out.println("[操作开始] " + operation + " - " + request.method() + " " + request.path());
}
private void logSuccess(String operation, ServerRequest request, ServerResponse response) {
System.out.println("[操作成功] " + operation + " - 状态码: " + response.statusCode());
}
private void logError(String operation, ServerRequest request, Exception e) {
System.out.println("[操作失败] " + operation + " - 错误: " + e.getMessage());
}
}
bash
package com.cqcloud.platform.handler;
import com.cqcloud.platform.common.matter.utils.Result;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.HandlerFilterFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
import java.util.Map;
import static org.springframework.http.MediaType.APPLICATION_JSON;
/**
* 权限检查处理器
* @author weimeilayer@gmail.com ✨
* @date 💓💕 2023年5月20日 🐬🐇 💓💕
*/
@Component
public class PermissionHandler {
/**
* 检查用户权限
* @param permission 需要的权限编码
* @return true=有权限,false=无权限
*/
public boolean hasPermission(String permission) {
// 实际项目中应从SecurityContext或Session中获取当前用户权限
// 这里模拟返回true,实际需要实现具体逻辑
return true;
}
/**
* 创建权限过滤器
* @param permission 权限编码
*/
public HandlerFilterFunction<ServerResponse, ServerResponse> requirePermission(String permission) {
return (request, next) -> {
if (hasPermission(permission)) {
return next.handle(request);
} else {
return ServerResponse.status(HttpStatus.FORBIDDEN)
.contentType(APPLICATION_JSON)
.body(Result.failed("权限不足,需要权限: " + permission));
}
};
}
/**
* 检查多个权限(满足任意一个即可)
* @param permissions 权限编码数组
*/
public HandlerFilterFunction<ServerResponse, ServerResponse> requireAnyPermission(String... permissions) {
return (request, next) -> {
for (String permission : permissions) {
if (hasPermission(permission)) {
return next.handle(request);
}
}
return ServerResponse.status(HttpStatus.FORBIDDEN)
.contentType(APPLICATION_JSON)
.body(Result.failed("权限不足"));
};
}
/**
* 动态权限检查(从请求参数中获取权限编码)
*/
public HandlerFilterFunction<ServerResponse, ServerResponse> dynamicPermissionCheck() {
return (request, next) -> {
// 从请求头、参数或路径中提取权限编码
String requiredPermission = extractPermissionFromRequest(request);
if (requiredPermission != null && !hasPermission(requiredPermission)) {
return ServerResponse.status(HttpStatus.FORBIDDEN)
.contentType(APPLICATION_JSON)
.body(Result.failed("权限不足"));
}
return next.handle(request);
};
}
private String extractPermissionFromRequest(ServerRequest request) {
// 根据请求路径和方法映射权限
Map<String, String> permissionMap = Map.of(
"POST /dept", "sys_dept_add",
"PUT /dept", "sys_dept_edit",
"DELETE /dept", "sys_dept_del"
);
String key = request.method().name() + " " + request.path();
return permissionMap.get(key);
}
}
bash
package com.cqcloud.platform.handler;
import com.cqcloud.platform.common.matter.utils.Result;
import com.cqcloud.platform.entity.SysDept;
import com.cqcloud.platform.service.SysDeptService;
import com.cqcloud.platform.vo.SysTreeVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.ServerResponse.*;
/**
* 系统基础信息--部门管理模块
* @author weimeilayer@gmail.com ✨
* @date 💓💕 2023年5月20日 🐬🐇 💓💕
*/
@Component
@RequiredArgsConstructor
public class SysDeptHandler {
private final SysDeptService deptService;
// 通过ID查询
public ServerResponse getById(ServerRequest request) {
String id = request.pathVariable("id");
SysDept dept = deptService.getById(id);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(dept));
}
// 添加部门
public ServerResponse save(ServerRequest request) throws Exception {
SysDept dept = request.body(SysDept.class);
boolean success = deptService.save(dept);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(success));
}
// 编辑部门
public ServerResponse update(ServerRequest request) throws Exception {
SysDept dept = request.body(SysDept.class);
boolean success = deptService.updateById(dept);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(success));
}
// 删除部门
public ServerResponse removeById(ServerRequest request) {
String id = request.pathVariable("id");
boolean success = deptService.removeDeptById(id);
if (success) {
return ok().contentType(APPLICATION_JSON)
.body(Result.success("删除成功"));
} else {
return badRequest().contentType(APPLICATION_JSON)
.body(Result.failed("删除失败"));
}
}
// 获取下级部门列表
public ServerResponse getDescendantList(ServerRequest request) {
String deptId = request.pathVariable("deptId");
List<SysDept> list = deptService.listDescendant(deptId);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(list));
}
// 获取部门树(原getDeptTree)
public ServerResponse getDeptTree(ServerRequest request) {
String parentId = request.param("parentId").orElse("-1");
Boolean lazyLoading = request.param("lazyLoading")
.map(Boolean::parseBoolean)
.orElse(true);
List<SysDept> tree = deptService.getDeptTree(parentId, lazyLoading);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(tree));
}
// 获取部门树(栈方式)
public ServerResponse getTree(ServerRequest request) {
String parentId = request.param("parentId").orElse("-1");
Boolean lazyLoading = request.param("lazyLoading")
.map(Boolean::parseBoolean)
.orElse(true);
List<SysTreeVo> tree = deptService.getTree(parentId, lazyLoading);
return ok().contentType(APPLICATION_JSON)
.body(Result.ok(tree));
}
}
bash
package com.cqcloud.platform.swagger;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.function.RouterFunction;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* 函数式路由的Swagger文档处理器
*/
@Configuration
@RequiredArgsConstructor
public class SwaggerRouterCustomizer {
@Bean
public OpenApiCustomizer routerSwaggerCustomizer() {
return openApi -> {
// 自动为路由函数添加文档
addDeptOperations(openApi);
addDictOperations(openApi);
};
}
/**
* 部门管理API文档
*/
private void addDeptOperations(OpenAPI openApi) {
// GET /dept/{id}
io.swagger.v3.oas.models.Operation getById = new io.swagger.v3.oas.models.Operation()
.summary("通过ID查询")
.description("通过ID查询部门详情")
.addParametersItem(new io.swagger.v3.oas.models.parameters.Parameter()
.name("id")
.in(String.valueOf(ParameterIn.PATH))
.required(true)
.schema(new Schema().type("string")))
.responses(new io.swagger.v3.oas.models.responses.ApiResponses()
.addApiResponse("200", new ApiResponse()
.description("成功")
.content(new Content().addMediaType("application/json",
new MediaType().schema(new Schema().$ref("#/components/schemas/Result<<SysDept>>"))))));
// POST /dept
io.swagger.v3.oas.models.Operation addDept = new io.swagger.v3.oas.models.Operation()
.summary("添加部门")
.description("添加新的部门")
.requestBody(new RequestBody()
.required(true)
.content(new Content().addMediaType("application/json",
new MediaType().schema(new Schema().$ref("#/components/schemas/SysDept")))))
.responses(new io.swagger.v3.oas.models.responses.ApiResponses()
.addApiResponse("200", new ApiResponse()
.description("成功")
.content(new Content().addMediaType("application/json",
new MediaType().schema(new Schema().$ref("#/components/schemas/Result<<boolean>>"))))));
// 添加到OpenAPI
if (openApi.getPaths() == null) {
openApi.setPaths(new io.swagger.v3.oas.models.Paths());
}
openApi.getPaths()
.addPathItem("/dept/{id}", new io.swagger.v3.oas.models.PathItem().get(getById))
.addPathItem("/dept", new io.swagger.v3.oas.models.PathItem().post(addDept));
}
private void addDictOperations(OpenAPI openApi) {
// 类似方式添加字典管理的API文档
}
}