Springdoc如何自定义EntityModel返回结果的_links节点Schema?
解决Springdoc生成EntityModel时_links多余属性的问题
以下是几种无需自定义Response类的实现方式:
方案1:自定义OpenAPI Schema修改器
通过实现OpenApiCustomiser接口,直接修改生成的OpenAPI规范中_links的Schema结构,只保留需要的链接和href属性:
import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.StringSchema; import org.springdoc.core.customizers.OpenApiCustomiser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class OpenApiConfig { @Bean public OpenApiCustomiser linksSchemaCustomiser() { return openApi -> { Components components = openApi.getComponents(); // 找到EntityModel对应的Schema(名称格式为EntityModelOf[实体类名],这里假设是EntityModelOfRecipe) ObjectSchema entityModelSchema = (ObjectSchema) components.getSchemas().get("EntityModelOfRecipe"); if (entityModelSchema != null) { // 自定义_links的Schema结构 ObjectSchema linksSchema = new ObjectSchema(); // 添加self链接,仅包含href ObjectSchema selfLinkSchema = new ObjectSchema(); selfLinkSchema.addProperty("href", new StringSchema().example("/recipes/{id}")); linksSchema.addProperty("self", selfLinkSchema); // 添加recipes链接 ObjectSchema recipesLinkSchema = new ObjectSchema(); recipesLinkSchema.addProperty("href", new StringSchema().example("/recipes")); linksSchema.addProperty("recipes", recipesLinkSchema); // 添加ingredients链接 ObjectSchema ingredientsLinkSchema = new ObjectSchema(); ingredientsLinkSchema.addProperty("href", new StringSchema().example("/recipes/{id}/ingredients")); linksSchema.addProperty("ingredients", ingredientsLinkSchema); // 替换原有的_links Schema entityModelSchema.addProperty("_links", linksSchema); } }; } }
方案2:配置Jackson序列化规则限制Link输出
通过自定义Jackson序列化器,让Link对象仅序列化href属性,Springdoc会基于此生成符合要求的示例:
- 编写自定义Link序列化器:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import org.springframework.hateoas.Link; import org.springframework.stereotype.Component; import java.io.IOException; @Component public class LinkSerializer extends JsonSerializer<Link> { @Override public void serialize(Link link, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); gen.writeStringField("href", link.getHref()); gen.writeEndObject(); } }
- 注册序列化器到Spring的ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.hateoas.Link; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper(LinkSerializer linkSerializer) { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new com.fasterxml.jackson.databind.module.SimpleModule() .addSerializer(Link.class, linkSerializer)); return mapper; } }
之后在接口中通过WebMvcLinkBuilder添加指定链接即可:
import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class RecipeController { @GetMapping("/recipes/{id}") public EntityModel<Recipe> getRecipe(@PathVariable Long id) { Recipe recipe = new Recipe(); // 业务逻辑获取实体 EntityModel<Recipe> entityModel = EntityModel.of(recipe); // 添加指定链接 entityModel.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(RecipeController.class).getRecipe(id)).withSelfRel()); entityModel.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(RecipeController.class).getAllRecipes()).withRel("recipes")); entityModel.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(RecipeController.class).getIngredients(id)).withRel("ingredients")); return entityModel; } // 省略getAllRecipes、getIngredients方法 }
方案3:直接用@Schema注解指定示例
在接口方法上通过@Schema注解直接定义返回示例,覆盖Springdoc自动生成的内容:
import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.hateoas.EntityModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class RecipeController { @GetMapping("/recipes/{id}") @Schema(example = "{\"id\": 1, \"name\": \"Tomato Soup\", \"_links\": {\"self\": {\"href\": \"/recipes/1\"}, \"recipes\": {\"href\": \"/recipes\"}, \"ingredients\": {\"href\": \"/recipes/1/ingredients\"}}}") public EntityModel<Recipe> getRecipe(@PathVariable Long id) { // 业务逻辑和添加链接的代码同上 return entityModel; } }
内容的提问来源于stack exchange,提问作者FilipK
相关产品推荐
相关产品推荐

