Spring Boot Web 在调用 API 时抛出 404,正确的项目结构

Spring Boot Web throws 404 with API call, correct project structure

已解决:在 CRUDServices.java 中添加 @Service 注释并在主应用程序中删除 @ComponentScan 解决了所有问题。

我有一个带有 Spring Boot Web、JPA 和 PostgreSQL 数据库的小型应用程序。 当尝试调用这些 API 调用中的任何一个时,我得到一个 404。在另一个应用程序中以相同的方式完成它是成功的。所有 类 都在同一个包中,我不明白为什么它找不到控制器(这似乎是大多数其他有 similair/same 问题的问题)。

它在端口 8081 上运行,因为我在端口 8080 上有另一个服务 运行。

我尝试删除 ComponentScan,但随后出现缺少 bean 异常。 我不明白 - 它们都在同一个包结构中?我只有一个包裹,那就是 booking.crudservice

主要应用

package booking.crudservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Service;

@SpringBootApplication
@ComponentScan(basePackages="booking.crudservice.CRUDservices")
public class CrudserviceApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(CrudserviceApplication.class, args);
    }
}

控制器

package booking.crudservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

/*
    This has PUT,POST, GET, DELETE requstest to the API endpoints for the CRUD operations
    in CRUDservices.java
 */

@RestController
@RequestMapping("/bookings")
public class BookingController
{
    @Autowired
    private CRUDServices services;

    //Return a specific booking by ID.
    @RequestMapping("/{bookingID}")
    public Optional<BookingEntity> getBookingByID(@PathVariable String bookingID)
    {
        return services.getBookingByID(bookingID);
    }

    //Return all bookings
    @RequestMapping("/allbookings")
    public List<BookingEntity> getAllBookings()
    {
        return services.getAllBookings();
    }

    @RequestMapping(method = RequestMethod.POST, value ="/addbooking")
    public void addBooking(@RequestBody BookingEntity booking)
    {
        services.addBooking(booking);
    }

    //Update a given booking (with a bookingID), and replace it with new BookingEntity instance.
    @RequestMapping(method = RequestMethod.PUT, value ="/bookings/{bookingID}")
    public void updateBooking(@RequestBody BookingEntity booking, @PathVariable String bookingID)
    {
        services.updateBooking(booking, bookingID);
    }

    //Deletes a booking with the given bookingID
    @RequestMapping(method = RequestMethod.DELETE, value ="/bookings/{bookingID}")
    public void deleteBooking(@PathVariable String bookingID)
    {
        services.deleteBooking(bookingID);
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>booking</groupId>
    <artifactId>crudservice</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>crudservice</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.properties 文件

server.port=8081
spring.datasource.url=jdbc:postgresql://localhost:5432/bookingDB
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL81Dialect

CRUDServices.java

package booking.crudservice;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/*
    This service holds all CRUD operations performed on the database.
    This utilizes the BookingRepository.java, which extends the CRUDrepository interface.
    Using ORM via JPA all operations on the database can be easily performed here.
    To connect to the web GET,PUT,POST and DELETE http requests will be made on all the operations via
    BookingController, enabling the user and other possible services to interact with the database
    using API endpoints.
 */

public class CRUDServices
{
    @Autowired
    private BookingRepository repository;

    //READ all bookings from DB using GET request
    public List<BookingEntity> getAllBookings()
    {
        List<BookingEntity> bookings = new ArrayList<>();
        repository.findAll().
                forEach(bookings::add);

        return bookings;
    }
    //SEARCH for a booking, given bookingID
    public Optional<BookingEntity> getBookingByID(String bookingID)
    {
        return repository.findById(bookingID);
    }

    public void addBooking(BookingEntity booking)
    {
        repository.save(booking);
    }

    public void updateBooking(BookingEntity booking, String bookingID)
    {
        //1. Search for the given ID in the database
        //2. Replace the booking object on that ID with new booking object from parameter.
    }

    public void deleteBooking(String bookingID)
    {
        repository.deleteById(bookingID);
    }
}

在 CrudserviceApplication class 中,您提到 base-package 为

@ComponentScan(basePackages="booking.crudservice.CRUDservices")

这意味着 spring 引导将寻找 class 带有 spring 刻板印象注释的 classes,例如

  • @组件
  • @配置
  • @控制器
  • @RestController
  • @服务

for classes 存在于 booking.crudservice.CRUDservices 包及其 sub-packages 中。 但是,我可以看到您的 BookingController class 存在于 booking.crudservice 包中,它不是 sub-package(实际上,它是父包)。

这就是为什么 spring 启动不扫描 BooKingController class 并且碰巧你得到 404。

作为修复,您可以删除 @ComponentScan 注释中的 basePackages 参数,它将扫描 booking.crudservice 及其 sub-package( s).

因为您的 CrudserviceApplication.class 存在于基本包本身中。您不必使用 @ComponentScan 注释。

您的服务 class (CRUDServices.class) 中应该有 @Service 注释,以便 spring 维护和注入它。

此外,您能否验证您正在调用所有带有 /bookings/yourhandlerendpoint 前缀的处理程序方法。你的情况

  • /bookings/{bookingID}
  • /bookings/allbookings
  • /bookings/addbooking
  • /bookings/bookings/{bookingID}
  • /bookings/bookings/{bookingID}

此外,我可以看到您为几种方法添加了两次 /bookings perfix。