I developed Spring Boot CRUD application. The database I have connected is PostgreSQL. @GetMapping is working properly and an empty array of objects can be retrieved by the GET request. But in @PostMapping, the POST request gives a 404 error.
📌SpringRecapApplication.java
package com.example.SpringRecap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
//@RequestMapping("api/v1/customers")
//@EnableWebMvc
@RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
public class SpringRecapApplication {
//dependency injection
private static CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public static void main(String[] args) {
SpringApplication.run(SpringRecapApplication.class, args);
}
@GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
record NewCustomerRequest(
String name,
String email,
Integer age
) {
@PostMapping
public void addCustomer(@RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
}
}
customerRepository.save(customer); doesn’t allow to make the dependency injection final. ( private static CustomerRepository customerRepository;). IDEA suggests making it static. But it didn’t work. When I was using @RequestMapping("api/v1/customers"), a 405 error was received. Then I fixed that issue by doing as below,
@RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
📌CustomerRepository.java
package com.example.SpringRecap;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer,Integer> {
}
📌Customer.java
package com.example.SpringRecap;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
public class Customer {
@Id
@SequenceGenerator(
name = "customer_id_sequence",
sequenceName = "customer_id_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "customer_id_sequence"
)
private Integer id;
private String name;
private String email;
private Integer age;
public Customer(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
public Customer() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
return Objects.equals(id, customer.id) && Objects.equals(name, customer.name) && Objects.equals(email, customer.email) && Objects.equals(age, customer.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, email, age);
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
Postman:
Please put a comment if further information is needed to get the solution.
>Solution :
The problem with your code is that you specified the POST endpoint as part of your DTO and not as part of your controller. As your DTO is not a Spring managed bean, Spring won’t map the URL to your endpoint. Anyways, you should move your endpoints into a seperate class. Example:
@RestController
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
@PostMapping
public void addCustomer(@RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
// Helper classes
record NewCustomerRequest(String name, String email, Integer age) { }
}
It would be best if you moved your DTO in a seperate class as well. I recommend placing the DTOs in a dto package and your controllers in a controller package.
Two side notes: you shouldn’t expose your entities via your API. You should use DTOs for incoming and outgoing data. Check out lombok and mapstruct, they make this pretty easy.
