如何用Spring Boot单端点接收不同类型请求负载?
解决Spring Boot单接口接收多类型RequestBody并兼容Swagger的方案
针对你需要用单个/download接口处理30种不同报表请求的场景,推荐用多态DTO+Jackson类型自动转换的方案,既能避免冗余接口,又能让Swagger生成清晰的API文档,替代之前用JsonNode的实现。
具体实现步骤
1. 定义多态请求基类
创建一个抽象基类,通过Jackson注解指定类型识别规则,让Spring能根据请求中的标识字段自动转成对应的子类:
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import java.time.LocalDate; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "reportType" // 用来区分报表类型的字段,比如传入"USER_REPORT"就转成UserReportRequest ) @JsonSubTypes({ @JsonSubTypes.Type(value = UserReportRequest.class, name = "USER_REPORT"), @JsonSubTypes.Type(value = OrderReportRequest.class, name = "ORDER_REPORT"), // 依次添加剩下28种报表的请求子类 }) public abstract class ReportRequest { // 所有报表共有的字段可以放在这里 private String downloadFormat; // 比如excel、pdf private LocalDate startDate; private LocalDate endDate; // getter、setter方法 }
2. 实现各报表的具体请求类
每个报表的专属参数定义成基类的子类:
// 用户报表请求 public class UserReportRequest extends ReportRequest { private Long userId; private String userRole; // getter、setter方法 } // 订单报表请求 public class OrderReportRequest extends ReportRequest { private String orderStatus; private Long merchantId; // getter、setter方法 }
3. 改造控制器接口
直接接收基类ReportRequest作为RequestBody,Spring会自动根据reportType字段转换为对应子类:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class ReportController { @PostMapping("/download") public ResponseEntity<?> download(@RequestBody ReportRequest request) { // 根据请求实例类型处理不同报表 if (request instanceof UserReportRequest) { UserReportRequest userReq = (UserReportRequest) request; // 处理用户报表下载逻辑 } else if (request instanceof OrderReportRequest) { OrderReportRequest orderReq = (OrderReportRequest) request; // 处理订单报表下载逻辑 } // 其他报表类型依次处理 return ResponseEntity.ok().build(); } }
4. 配置Swagger兼容多态文档
如果用的是SpringDoc(Swagger 3),在配置类中显式注册所有子类的Schema,让Swagger能展示所有可能的请求体结构:
import org.springdoc.core.utils.SpringDocUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Components; @Configuration public class SwaggerConfig { static { // 注册所有报表请求子类,让Swagger识别多态类型 SpringDocUtils.getConfig().addRestControllers(ReportController.class); SpringDocUtils.getConfig().addRequestWrapperToIgnore(ReportRequest.class); } @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .components(new Components() .addSchemas("UserReportRequest", SpringDocUtils.getConfig().getSchema(UserReportRequest.class)) .addSchemas("OrderReportRequest", SpringDocUtils.getConfig().getSchema(OrderReportRequest.class)) // 依次添加其他报表请求子类 ); } }
如果用的是Springfox(Swagger 2),可以在基类和子类上添加@ApiModel注解:
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @ApiModel(description = "报表请求基类", subTypes = {UserReportRequest.class, OrderReportRequest.class}) @JsonTypeInfo(...) @JsonSubTypes(...) public abstract class ReportRequest { @ApiModelProperty("下载格式:excel/pdf") private String downloadFormat; // ...其他字段 } @ApiModel("用户报表请求") public class UserReportRequest extends ReportRequest { @ApiModelProperty("用户ID") private Long userId; // ...其他字段 }
方案优势
- 避免创建30个重复接口,代码结构更简洁
- Spring自动完成类型转换,无需手动解析Json
- Swagger能完整展示所有报表的请求体结构,API文档清晰
- 后续新增报表只需添加对应的子类和配置,扩展性强
内容的提问来源于stack exchange,提问作者semicolon
相关产品推荐
相关产品推荐

