繁体   English   中英

Spring 引导 - 将存储库注入 Controller 抛出考虑在配置中定义类型为“Type”的 bean

[英]Spring Boot - Injecting Repository into Controller throws Consider defining a bean of type 'Type' in your configuration

我有一个 Spring/Boot REST controller 我将存储库注入如下:

package com.example.schooltimetable.controllers;

import com.example.schooltimetable.models.entities.StudentEntity;
import com.example.schooltimetable.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin
@RequestMapping("student")
public class StudentController {

    private final StudentRepository studentRepository;

    @Autowired
    public StudentController(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    @RequestMapping(value = "/getAll", method = RequestMethod.GET)
    public Iterable<StudentEntity> getAllStudents() {
        return this.studentRepository.findAll();
    }
}

我面临的问题是,每当我启动我的应用程序时,它都会引发以下错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.schooltimetable.controllers.StudentController required a bean of type 'com.example.schooltimetable.repository.StudentsRepository' that could not be found.


Action:

Consider defining a bean of type 'com.example.schooltimetable.repository.StudentsRepository' in your configuration.


Process finished with exit code 1

我在尝试在另一个 class 中查找实体之前遇到了这个问题,我通过使用Application.java中的@ComponentScan()注释解决了这个问题,但是,它无法解决这个问题。

我的主应用程序文件如下所示:

学校时间表申请

package com.example.schooltimetable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan({
    "com.example.schooltimetable.controllers",
    "org.springframework.stereotype",
    "com.example.schooltimetable.repository",
})
public class SchoolTimetableApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchoolTimetableApplication.class, args);
    }
}

我的存储库看起来像这样:StudentRepository

package com.example.schooltimetable.repository;

import com.example.schooltimetable.models.entities.StudentEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

@Repository
@Component
public interface StudentRepository extends CrudRepository<StudentEntity, Long> { }

存储库中引用的 StudentEntity:

package com.example.schooltimetable.models.entities;

import com.example.schooltimetable.models.constants.StudentEntityConstants;
import com.example.schooltimetable.models.constants.TimetableEntityConstants;
import org.springframework.lang.NonNull;

import javax.persistence.*;
import java.util.UUID;

@Entity
@Table(name = StudentEntityConstants.TABLE_NAME)
public class StudentEntity {

    @Id
    @Column(name = StudentEntityConstants.ID)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = StudentEntityConstants.FIRST_NAME)
    @NonNull
    private String firstName;

    @Column(name = StudentEntityConstants.LAST_NAME)
    @NonNull
    private String lastName;

    @Column(name = StudentEntityConstants.REFERENCE)
    @NonNull
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID reference;

    @OneToOne(targetEntity = TimeTableEntity.class)
    @JoinColumn(name = TimetableEntityConstants.REFERENCE)
    private TimeTableEntity timeTable;

    public long getId() {
        return this.id;
    }

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

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public UUID getReference() {
        return this.reference;
    }

    public void setReference(UUID reference) {
        this.reference = reference;
    }

    public TimeTableEntity getTimeTable() {
        return this.timeTable;
    }
}

还有我的 POM 文件:

<?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.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>school-timetable</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>school-timetable</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
            <version>2.3.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

是不是我做错了什么? 我对 Spring/Boot 很陌生。 这个问题的一个有趣的注释是,如果我删除

@ComponentScan({
    "com.example.schooltimetable.controllers", <---- This
    "org.springframework.stereotype",
    "com.example.schooltimetable.repository",
})

然后应用程序加载,但 controller 在尝试命中时会抛出 404: http://localhost:8080/student/getAll

编辑!!!

此时应用程序出现了一些问题。 首先,POM 文件需要更新

<?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.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>school-timetable</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>school-timetable</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-configuration</groupId>
            <artifactId>commons-configuration</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

其次,MAIN CLASS

package com.example.schooltimetable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@PropertySource("classpath:application.properties")
@EntityScan("com.example.schooltimetable.models.entities")
@EnableJpaRepositories("com.example.schooltimetable.repository")
public class SchoolTimetableApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchoolTimetableApplication.class, args);
    }
}

加入列时实体也有问题:它们应该设置为读写:false

package com.example.schooltimetable.models.entities;

import com.example.schooltimetable.models.constants.StudentEntityConstants;
import com.example.schooltimetable.models.constants.TimetableEntityConstants;
import org.springframework.lang.NonNull;

import javax.persistence.*;
import java.util.UUID;

@Entity
@Table(name = StudentEntityConstants.TABLE_NAME)
public class StudentEntity {

    @Id
    @Column(name = StudentEntityConstants.ID)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = StudentEntityConstants.FIRST_NAME)
    @NonNull
    private String firstName;

    @Column(name = StudentEntityConstants.LAST_NAME)
    @NonNull
    private String lastName;

    @Column(name = StudentEntityConstants.REFERENCE)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID reference;

    @OneToOne(targetEntity = TimeTableEntity.class)
    @JoinColumn(name = TimetableEntityConstants.REFERENCE, updatable = false, insertable = false)
    private TimeTableEntity timeTable;

    public long getId() {
        return this.id;
    }

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

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public UUID getReference() {
        return this.reference;
    }

    public void setReference(UUID reference) {
        this.reference = reference;
    }

    public TimeTableEntity getTimeTable() {
        return this.timeTable;
    }
}

感谢@Abhinaba Chakraborty 为我指明了正确的方向

首先,您不需要使用注释SpringBootApplication进行组件扫描。 Spring 自动扫描所有使用 Component、Service、RestController、Respository、Configuration 等注释的组件并创建 Bean。

StudentController 中的请求映射注释值应以“/”为前缀,例如。 @RequestMapping("/student") - 虽然它与依赖注入无关。 但这就是您在 http://localhost:8080/student/getAll 获得 404 的原因

在存储库接口中,只需使用@Repository 注解,而不是同时使用@Repository 和@Component 注解。

此外,我还没有看到在您的 POM.xml 中定义的 data-jpa 依赖项,您如何在存储库中导入org.springframework.data.repository.CrudRepository 你需要那种依赖。

就目录结构而言,它看起来不错,但请验证:

固定的!!!

所以问题在于我在学生和时间表之间实现@OneToOne关系的方式。

正如@M.Deinum 所述,问题中的编辑是一种解决方法。 正确的解决方案是首先清理 Student 和 Timetable 之间的关系,如下所示:

StudentEntity

package com.example.schooltimetable.models.entities;

import com.example.schooltimetable.models.constants.StudentEntityConstants;
import org.springframework.lang.NonNull;

import javax.persistence.*;

@Entity
@Table(name = StudentEntityConstants.TABLE_NAME)
public class StudentEntity {

    @Id
    @Column(name = StudentEntityConstants.ID)
    private long id;

    @Column(name = StudentEntityConstants.FIRST_NAME)
    @NonNull
    private String firstName;

    @Column(name = StudentEntityConstants.LAST_NAME)
    @NonNull
    private String lastName;

    @OneToOne(mappedBy = "student", cascade = CascadeType.ALL) // no need to join the columns on the Student. 
    private TimeTableEntity timeTable;

    public long getId() {
        return this.id;
    }

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

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public TimeTableEntity getTimeTable() {
        return this.timeTable;
    }

    public void setTimeTable(TimeTableEntity timeTable) { this.timeTable = timeTable; }
}

TimeTableEntity

package com.example.schooltimetable.models.entities;

import com.example.schooltimetable.models.constants.TimetableEntityConstants;

import javax.persistence.*;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;

@Entity
@Table(name = TimetableEntityConstants.TABLE_NAME)
public class TimeTableEntity implements Serializable {

    @Id
    @Column(name = TimetableEntityConstants.ID)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToOne
    @MapsId // <-- This automatically knows to join by the student ID column
    private StudentEntity student;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private final Set<ModuleEntity> modules = new LinkedHashSet();

    public long getId() {
        return this.id;
    }

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

    public void setStudent(StudentEntity student) {
        this.student = student;
    }

    public Set<ModuleEntity> getModules() {
        return this.modules;
    }

    public void setModules(ModuleEntity module) {
        this.modules.add(module);
    }
}

现在,接下来的几个重构,我可以做,我不知道为什么它会突然起作用,但我感觉这与错误的实体设置有关。我能够删除@EntityScan("com.example.schooltimetable.models.entities") & @EnableJpaRepositories("com.example.schooltimetable.repository")

我的主要 class 中的注释,我还能够从我的代码中删除很多@Scope@Component注释。 我的主要 class 现在看起来像这样:

SchoolTimetableApplication

package com.example.schooltimetable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
@PropertySource("classpath:application.properties")
public class SchoolTimetableApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchoolTimetableApplication.class, args);
    }
}

好多了! 我也有数据通过关系而不是null (我面临的另一个问题)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM