“status”:Spring Boot CRUD 中 POST 请求的 404 错误

"status": 404 Error for POST Request in Spring Boot CRUD

提问人:Nimasha Madhushani 提问时间:1/20/2023 最后编辑:Christian BaumannNimasha Madhushani 更新时间:1/20/2023 访问量:460

问:

我开发了Spring Boot CRUD应用程序。我连接的数据库是 PostgreSQL。 工作正常,GET 请求可以检索空的对象数组。但是在 中,POST 请求给出了 404 错误。@GetMapping@PostMapping

📌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);不允许使依赖注入成为最终结果。( ).IDEA建议将其设置为静态。但它没有用。当我使用时,收到 405 错误。然后我通过执行以下操作解决了该问题,private static CustomerRepository customerRepository;@RequestMapping("api/v1/customers")

 @RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)

📌客户存储库.java

package com.example.SpringRecap;

import org.springframework.data.jpa.repository.JpaRepository;

public interface CustomerRepository extends JpaRepository<Customer,Integer> {
}

📌客户 .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 image

如果需要更多信息来获得解决方案,请发表评论。

java postgresql spring-boot http-post

评论

0赞 Govil Kumar 1/20/2023
将此@RequestMapping(name = “api/v1/customers” ,method = RequestMethod.POST) 更改为 @RequestMapping(name = “/api/v1”) 和 @GetMapping(“/customers”)。这应该有效。此外,请确保应用程序在端口 3000 上运行。
0赞 Nimasha Madhushani 1/20/2023
我已经清楚地提到了我在 Postman 中截屏时遇到的错误所做的要点,然后我将删除您提到的部分。@jsotola
0赞 Nimasha Madhushani 1/20/2023
@GovilKumar我按照你提到的做了,但它不起作用。应用程序在端口 3000 上运行。并且GET请求在我的代码中正常工作,我在问题中提到过。
0赞 Govil Kumar 1/20/2023
那是我的错,我的意思是在@PostMapping(“/customers”)
0赞 Nimasha Madhushani 1/20/2023
@Govil Kumar 不,这不是你的坏事。我尝试了@PostMapping(“/customers”),但没有用

答:

3赞 times29 1/20/2023 #1

代码的问题在于,您将 POST 端点指定为 DTO 的一部分,而不是控制器的一部分。由于 DTO 不是 Spring 托管的 Bean,因此 Spring 不会将 URL 映射到您的端点。无论如何,您应该将终结点移动到单独的类中。例:

@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) { }

}

最好将 DTO 也移动到单独的类中。我建议将 DTO 放在包中,将控制器放在包中。dtocontroller

两个旁注:你不应该通过你的 API 暴露你的实体。应将 DTO 用于传入和传出数据。看看龙目岛mapstruct,它们使这变得非常容易。

评论

0赞 Nimasha Madhushani 1/20/2023
我想你已经提到龙目岛@Data注释来删除 getters setter,...等。
0赞 phaen 1/20/2023
我更喜欢使用 DTO 的记录 - 自 Java17 IMO 以来,龙目岛的使用被高估了
0赞 Nimasha Madhushani 1/20/2023
我尝试过 DTO。它正在工作。但@Autowired应该用于连接 CustomerRepository。在构造函数中,我不得不使用 void。但是,构造函数通常没有返回类型。我假设 void 在那里工作,因为 void 不返回任何内容。@倍29
0赞 Nimasha Madhushani 1/20/2023
谢谢,@times29的支持。现在它正在工作。正如我在上面的评论中提到的,我对你的代码做了一个小改动
0赞 times29 1/20/2023
@NimashaMadhushani,如果你的类中只有构造函数,则不需要注释。另外,请查看这篇文章,了解为什么你应该更喜欢构造函数注入而不是其他机制: reflectoring.io/constructor-injection@Autowired