I create a CRUD application using SpringBoot. I use PostgreSQL as a database. My application also uses SpringSecurity. The methods of displaying and creating objects work perfectly. But for some reason, updating and deleting the same objects gives an error:
2022-11-01 08:51:14.602 WARN 12149 --- [io-8080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
I think the problem is in the html code. I use Thymeleaf.
**My Student Controller: **
package ru.connor.FirstSecurityApp.controllers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import ru.connor.FirstSecurityApp.model.Student;
import ru.connor.FirstSecurityApp.services.StudentService;
import javax.validation.Valid;
import java.util.Optional;
@Controller
@RequestMapping("/students")
@RequiredArgsConstructor
public class StudentController {
private final StudentService studentService;
@GetMapping()
public String showAllClasses(Model model) {
model.addAttribute("students", studentService.showAllStudent());
return "main/AllClasses";
}
@GetMapping("/{id}")
public String showById(@PathVariable("id") int id, Model model){
Optional<Student> student = Optional.ofNullable(studentService.showStudentById(id));
if (student.isEmpty()){
return "main/students/errorPage";
}else model.addAttribute("student", student);
return "main/students/index";
}
@GetMapping("/add")
public String addStudent(@ModelAttribute("student") Student student) {
return "main/students/new";
}
@PostMapping()
public String create(@ModelAttribute("student") @Valid Student student,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "main/students/new";
studentService.addStudent(student);
return "redirect:/students";
}
@GetMapping("/{id}/edit")
public String edit(Model model, @PathVariable("id") int id) {
model.addAttribute("student", studentService.showStudentById(id));
return "main/students/edit";
}
@PatchMapping("/{id}")
public String update(@ModelAttribute("student") @Valid Student student, BindingResult bindingResult, @PathVariable("id") int id) {
if (bindingResult.hasErrors()){
return "main/students/edit";}
studentService.update(id, student);
return "redirect:/students";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable("id") int id){
Optional<Student> student = Optional.ofNullable(studentService.showStudentById(id));
if (student.isPresent()){
studentService.delete(id);
return "redirect:/students";
}
return "main/students/index";
}
}
Student Service:
package ru.connor.FirstSecurityApp.services;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.connor.FirstSecurityApp.model.Student;
import ru.connor.FirstSecurityApp.repository.StudentsRepository;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@SuppressWarnings("unused")
@Transactional(readOnly = true)
public class StudentService {
private final StudentsRepository studentsRepository;
public List<Student> showAllStudent(){
return studentsRepository.findAll();
}
public Student showStudentById(int id){
Optional<Student> foundPerson = studentsRepository.findById(id);
return foundPerson.orElse(null);
}
@Transactional
public void addStudent(Student student){
studentsRepository.save(student);
}
@Transactional
public void update(int id, Student person){
person.setId(id);
studentsRepository.save(person);
}
@Transactional
public boolean delete(int id){
if (studentsRepository.findById(id).isPresent()){
studentsRepository.deleteById(id);
return true;
}
return false;
}
}
**HTML view where the delete form is specified: **
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Student</title>
</head>
<body>
<h1 th:text="${student.get().getFullStudentName()}"></h1>
<hr>
<form method="post" th:action="@{/students/{id}(id=${student.get().getId()})}">
<input type="submit" value="Delete">
</form>
</body>
</html>
CodePudding user response:
As you have mentioned @PatchMapping
for updates then you need the HTTP PATCH method instead of POST. The same goes for delete you have used @DeleteMapping
, so you need to use the HTTP DELETE method instead of POST.
Create -> POST
Read -> GET
Update -> PUT/PATCH
Delete -> DELETE
With form submit I don't think PATCH/PUT/DELETE will work so in that case you need to change @PatchMapping
/@DeleteMapping
to @PostMapping
and update the URL so it will be unique for update/delete.
PUT/PATCH/DELETE will work with REST API only.