@PostMapping с несколькими телами запросов

#java #mysql #spring #hibernate #post

#java #mysql #весна #переход в спящий режим #Публикация

Вопрос:

Я очень новичок в Java Spring и у меня небольшая проблема.

Я не хочу отправлять employee_id (из объекта employees) в объект назначения в части тела (в Postman). В настоящее время это работает, потому что я отправляю employee_id в качестве переменной пути и отправляю данные назначения с ResponseBody.

 @PostMapping("/add/{employee_id}")
   public void addEmployee(@PathVariable(value = "employee_id", required = false) Long employee_id, 
             @RequestBody Assignment a) {

       Employee employeeById = employeeRepository.findById(employee_id)
               .orElseThrow(() -> new RuntimeException("Employee not found"));

       a.setEmployee(employeeById);
       assignmentRepository.addAssignment(a);
   }
  

Он работает с URL localhost:8080/add/35. 35 — это employee_id, и данные назначения могут быть отправлены в теле (Postman). Что я хочу сделать, так это отправить employee_id и в теле (поэтому URL должен быть только / add), но я не смог заставить его работать.

Вот так:

 {
  "employee_id": 35,
  "title": "abc"
}

  

Отредактировано:

Assignment.java

 public class Assignment {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Integer id;

   @OneToOne(optional = false)
   @JoinColumn(name = "employee_id", nullable = false)
   private Employee employee;

   @Size(min = 3, max = 50)
   private String assignment_title;

   public Assignment() {
   }

   public Assignment(String assignment_title) {
       super();
       this.assignment_title = assignment_title;
   }

   public Integer getId() {
       return id;
   }

   public void setId(Integer id) {
       this.id = id;
   }

   public String getAssignment_title() {
       return assignment_title;
   }

   public void setAssignment_title(String assignment_title) {
       this.assignment_title = assignment_title;
   }

   public Employee getEmployee() {
       return employee;
   }

   public void setEmployee(Employee employee) {
       this.employee = employee;
   }
}
  

AssignmentService.java

    public void addAssignment(Assignment e) {
       AssignmentRepository.save(e);
   }
  

AssignmentRepository.java

 public interface AssignmentRepository extends CrudRepository<Assignment, Integer>{
   
}

  

Employee.java

 public class Employee{
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Integer id;
   
   @OneToOne(optional = false)
   @JoinColumn(name = "user_id", nullable = false)
   private User user;

   @Size(min=3, max = 100)
   private String title;

   @Size(min=3, max = 50)
   private String staff;

   private Long degree;

   public Employee() {}

   public Employee( String title, String staff, Long degree) {
       super();
       this.title = title;
       this.staff = staff;
       this.degree = degree;
   }
   
   public Integer getId() {
       return id;
   }

   public void setId(Integer id) {
       this.id = id;
   }

   public String getTitle() {
       return title;
   }

   public void setTitle(String title) {
       this.title = title;
   }

   public String getStaff() {
       return staff;
   }

   public void setStaff(String staff) {
       this.staff = staff;
   }

   public Long getDegree() {
       return degree;
   }

   public void setDegree(Long degree) {
       this.degree = degree;
   }

   public User getUser() {
       return user;
   }

   public void setUser(User user) {
       this.user = user;
   }

}

  

EmployeeRepository.java

 public interface EmployeeRepository extends CrudRepository<Employee, Integer>{
   Optional<Employee> findById(Long id);
}


  

Заранее спасибо за вашу помощь!

Ответ №1:

Вам необходимо убедиться, что ваш тип тела Assignment обладает таким свойством, как

 public class Assignment {
    public Long employee_id;
    // ommitted
}
  

И получите это в своем методе, например

 @PostMapping("/add")
public void addEmployee(@PathVariable(value = "employee_id", required = false) Long employee_id, @RequestBody Assignment a) {
    Long employee_id = a.employee_id;
    Employee employeeById = employeeRepository.findById(employee_id)
        .orElseThrow(() -> new RuntimeException("Employee not found"));
    a.setEmployee(employeeById);
    assignmentRepository.addAssignment(a);
}
  

Но такая реализация не соответствует стандартам HTTP.
Пожалуйста, учтите, что ваша фактическая реализация почти соответствует этим стандартам, и вам следует переименовать свой API таким образом : POST URL/v1/employees/{employee_id}
Этот блог объясняет эти стандарты

РЕДАКТИРОВАТЬ с предоставленными спецификациями:

 @PostMapping(values = {"/v1/employees", "/v1/employees/{employee_id}"})
public void addEmployee(@PathVariable(value = "employee_id", required = false) Long employee_id, @RequestBody Assignment a) {
    Long yourId = employee_id != null ? employee_id : a.employee_id;
    if (yourId == null) {
        throw new RuntimeException("No id given"); // Not clean either but implemented by OP
    } else {
        Employee employeeById = employeeRepository.findById(yourId)
            .orElseThrow(() -> new RuntimeException("Employee not found"));
        a.setEmployee(employeeById);
        assignmentRepository.addAssignment(a);
    }
}
  

Поскольку переменный путь является необязательным, вы пытаетесь получить его сначала из URL, а затем из вашего объекта body.

РЕДАКТИРОВАТЬ 2: Assignment может быть создано без Employee_id
Первый случай: вы соглашаетесь с тем, что у назначения может не быть сотрудника.
Просто измените свое отношение с назначения на сотрудника :

     @OneToOne(optional = true)
    @JoinColumn(name = "employee_id", nullable = true)
    private Employee employee;
  

Второй случай: вы хотите сначала создать нового сотрудника, а затем привязать его к своему назначению, поскольку Assignment всегда должен иметь Employee

 @PostMapping(values = {"/v1/employees", "/v1/employees/{employee_id}"})
public void addEmployee(@PathVariable(value = "employee_id", required = false) Long employee_id, @RequestBody Assignment a) {
    Long yourId = employee_id != null ? employee_id : a.employee_id;
    Employee employeeById = yourId != null ?
        employeeRepository.findById(yourId).orElseThrow(() -> new RuntimeException("Employee not found"))
        : new Employee("title","staff",2L);
    a.setEmployee(employeeById);
    assignmentRepository.addAssignment(a);
}
  

Комментарии:

1. Спасибо. Но таким образом я не могу присвоить employee_id значение null. В некоторых сценариях администратор может отказаться от добавления сотрудника в назначение. Как я могу это исправить?

2. ping @Rosina вы должны предоставить несколько сопоставлений в своем @PostMapping

3. Таким образом, я ничего не изменил, все по-прежнему так, как в моем вопросе, я просто добавил отредактированную версию из вашего кода (переменный путь и длинный yourrid). Но я все еще получаю следующую ошибку: указанный идентификатор не должен быть нулевым!

4. Затем вы должны вызвать свой репозиторий с помощью yourId . И убедитесь, что оно не равно нулю перед началом.

5. Таким образом, это просто выдает ошибку. Я хочу добавить назначение, даже если employee_id не задан, если его значение равно нулю. Я просто попытался поместить assignmentRepository.addAssignment(a); в функцию if. Это тоже не работает. Но я могу добавить назначение с employee_id, проблем нет