在 Spring 引导中使用 post 方法保存多个实体时无限循环

Infinite loop when saving multiple entities with a post-method in Spring boot

为了解释我正在处理的问题,我将首先提供代码。

配方控制器

@RequestMapping(path = "/addrecipe")
public void addNewRecipe(@RequestBody AddRecipeDto addRecipeDto){
    Recipe newRecipe = new Recipe();
    EvaUser user = evaUserRepository.findOne(addRecipeDto.getUserId());
    for(Ingredient ingredient: addRecipeDto.getIngredients()){
        ingredientRepository.save(ingredient);
    }
    newRecipe.setTitle(addRecipeDto.getTitle());
    newRecipe.setAuthor(user);
    newRecipe.setDescription(addRecipeDto.getDescription());
    newRecipe.setIngredients(addRecipeDto.getIngredients());
    recipeRepository.save(newRecipe);
    user.getMyRecipes().add(newRecipe);
    evaUserRepository.save(user);
}

用户控制器

@RequestMapping("/getusers")
public Iterable<EvaUser> getAllUsers() {
    return evaUserRepository.findAll();
}

EvaUser

@OneToMany
private List<Recipe> myRecipes;

@ManyToMany
private List<Recipe> favoriteRecipes;

食谱

@ManyToOne
private EvaUser author;

异常

Failed to write HTTP message: 
org.springframework.http.converter.HttpMessageNotWritableException: Could 
not write content: Infinite recursion

问题

所以当我调用添加菜谱的方法时,我想让数据库知道有一个新菜谱,并且新菜谱链接到添加它的用户。当我删除保存用户实体的部分时,根本不会进行映射。但是当我使用 userRepository 告诉数据库已经进行了更改(将食谱添加到他们的列表中)时,似乎存在添加新用户的无限循环。

回答您的问题并包括您评论中的最后要求。

如果你想打破循环,但有些人又想保留嵌套对象,我建议编写一个自定义序列化程序,并将导致无限递归的对象替换为其他字段(我使用作者用户名这是 String 而不是下面示例中的 Author 对象)。

为了重现案例,我创建了一个类似于您的模拟模型。

食谱:

public class Recipe {

    private EvaUser author;
    private String name = "test";
    private String ingridients = "carrots, tomatos";

    public EvaUser getAuthor() {
        return author;
    }

    public void setAuthor(EvaUser author) {
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIngridients() {
        return ingridients;
    }

    public void setIngridients(String ingridients) {
        this.ingridients = ingridients;
    }
}

EvaUser:

public class EvaUser {

    private List<Recipe> myRecipes = new ArrayList<>();
    private List<Recipe> favoriteRecipes = new ArrayList<>();
    private String username;

    public List<Recipe> getMyRecipes() {
        return myRecipes;
    }

    public void setMyRecipes(List<Recipe> myRecipes) {
        this.myRecipes = myRecipes;
    }

    public List<Recipe> getFavoriteRecipes() {
        return favoriteRecipes;
    }

    public void setFavoriteRecipes(List<Recipe> favoriteRecipes) {
        this.favoriteRecipes = favoriteRecipes;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

正在创建自定义序列化程序:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.util.Optional;

public class RecipeSerializer extends StdSerializer<Recipe> {

    protected RecipeSerializer() {
        this(null);
    }

    protected RecipeSerializer(Class<Recipe> t) {
        super(t);
    }

    @Override
    public void serialize(Recipe recipe, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();

        gen.writeStringField("name", recipe.getName());
        gen.writeStringField("author", Optional.ofNullable(recipe.getAuthor().getUsername()).orElse("null"));
        gen.writeStringField("ingridients", recipe.getIngridients());

        gen.writeEndObject();
    }
}

正在应用序列化器:

@JsonSerialize(using = RecipeSerializer.class)
public class Recipe {
    // model entity
}

JSON 来自控制器的 EvaUser 的响应主体(前一个是 WhosebugError):

{
    "myRecipes": [
        {
            "name": "soup",
            "author": "user1",
            "ingridients": "carrots, tomatos"
        },
        {
            "name": "steak",
            "author": "user1",
            "ingridients": "meat, salt"
        }
    ],
    "favoriteRecipes": [
        {
            "name": "soup",
            "author": "user1",
            "ingridients": "carrots, tomatos"
        },
        {
            "name": "steak",
            "author": "user1",
            "ingridients": "meat, salt"
        }
    ],
    "username": "user1"
}