首页 > 解决方案 > Spring:如何将请求发布到多对多关系中

问题描述

我有两个实体,Meal并且Mealplan在 @ManyToMany 关系中。每个 Mealplan 包含五个 Meal 对象。

一顿饭:

@Entity
public class Meal {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
    private BigDecimal price;
    private String type;

    @ManyToMany(mappedBy = "mealsPerWeek")
    private List<Mealplan> mealplan;
}

进食计划:

public class Mealplan {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private int calendarweek;

    @ManyToMany
    private List<Meal> mealsPerWeek;

例如的 JSON/mealplan/1如下所示:

{
id: 1,
calendarweek: 10,
mealsPerWeek: [
   {
   id: 4,
   name: "Linsensuppe",
   price: 23.5,
   art: "vegan"
   },
   {
   id: 3,
   name: "Salat",
   price: 3,
   art: "vegetarisch"
   },

现在我想创建一个(自定义?)方法来将膳食添加到膳食计划中。最好的方法是什么?我正在考虑我的存储库中的自定义方法,如下所示:

@RestController
@RequestMapping("/mealplan")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class MealplanController {

    @PostMapping
    public void addMealToMealplan(@RequestBody Meal meal) {
        mealplanRepository.addMealToMealplan(essen);
    }

但是如何将此自定义方法添加到存储库中?一个高性能的方法看起来如何?

@Repository
public interface MealplanRepository extends JpaRepository<Mealplan, Integer> {

 void addMealToMealplan(Meal meal);
}

不起作用,例如,我不能在接口中声明方法。我需要一个新的班级吗?

标签: javaspringjpaspring-data-jpa

解决方案


我会用这样的东西:

确保创建 MealRepository jpa 接口

@Repository
public interface MealRepository extends JpaRepository<Meal, Integer> {
}

然后最好创建 MealPlanService 来处理对象上的任何操作(而不是在控制器中进行实际工作),注入两个存储库。每当我们添加新餐点时,我们都会先将其持久化,然后添加到餐点计划对象上的餐点集合中。自动更新膳食计划的事务性(您可以在膳食计划上手动调用保存)

@Service
public class MealPlanService{
    private MealRepository  _mealRepository;
    private MealPlanRepository _mealPlanRepository;

    @Autowire
    MealPlanService(MealRepository mealRepository,MealPlanRepository mealPlanRepository)
      _mealRepository = mealRepository
      _mealPlanRepository = mealPlanRepository
    }

    @Transactional
    public Mealplan addMealToMealplan(int mealPlanId, Meal meal) throws MealNotFoundException{
          Mealplan mealplan = _mealPlanRepository.findById(mealPlanId).orElseThrow(MealNotFoundException::new)
          meal = _mealRepository.save(meal); 
          mealplan.getMealsPerWeek().add(meal)
          return mealplan;
    }
}

并在 Controller 中自动装配服务并执行。如果有人试图改变现有的膳食计划,或者不是他的(在服务中有一些额外的逻辑),你可以额外保护和优雅地捕捉它的好东西

@RestController
@RequestMapping("/mealplan")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class MealplanController {
    private MealPlanService _mealPlanService;

    @Autowire
    MealplanController (MealPlanService mealPlanService){
            _mealPlanService = mealPlanService;
    }

    @PostMapping(path = "/{mealPlanId}/add")
    public ResponseEntity<MealPlan> addMealToMealplan(@PathVariable int mealPlanId , @RequestBody Meal meal) {
            try{
                 return ResponseEntity.ok(_mealPlanService.addMealToMealplan(meal));
            catch (MealNotFoundException e){
                 //do some other logic, return error , log it or smth
                 ResponseEntity.notFound().build();
            }
    } 

POST 请求/mealplan/1/add与新餐的主体(其中 1 是您mealPlanId应该添加的餐点)。

控制器将调用服务服务,该服务将尝试首先根据传递的 id 找到膳食计划 _mealPlanRepository.findById(mealPlanId)

这将返回 Optional 并且我们通过调用链接获取值的操作_mealPlanRepository.findById(mealPlanId).orElseThrow(MealNotFoundException::new)

在找到的实体上,我们然后添加我们的新餐(由于 Transactional 它将被持久化,但您可以调用_mealPlanRepository.save()它而不是

如果一切都正确完成,则服务 retus 更新实体,然后控制器返回带有更新膳食计划的响应实体


推荐阅读