使用 Spring Boot + Jpa + vaadin 保存表单数据时出现问题
Issue when saving form data using SprinBoot + Jpa + vaadin
我正在使用 SpringBoot 以及 JPA 和 Vaadin-flow。我在尝试保存表单数据时遇到此错误。
我尝试在 CustomerRepository class 中添加 @Repository 注解,但仍然无法正常工作。有人可以帮我解决这个问题吗?
Customer.java
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
//Getters ans Setters
}
CustomerEditor.java
@Route(value = "NewPickUp", layout = MainView.class)
@SpringComponent
@UIScope
public class CustomerEditor extends VerticalLayout{
@Autowired
private final CustomerRepository repository;
@Autowired
private Customer customer;
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
Button save = new Button("Save", VaadinIcon.CHECK.create());
Binder<Customer> binder = new Binder<>(Customer.class);
@Autowired
public CustomerEditor(CustomerRepository repository) {
this.repository = repository;
add(firstName, lastName, save );
binder.forField(firstName).bind(Customer::getFirstName, Customer::setFirstName);
binder.forField(lastName).bind(Customer::getLastName, Customer::setLastName);
save.addClickListener(e -> save());
}
void save() {
repository.save(customer);
}
}
CustomerRepository.java
public interface CustomerRepository extends JpaRepository<Customer, Long> {
List<Customer> findByLastNameStartsWithIgnoreCase(String lastName);
}
MainView.java
@Route
public class MainView extends AppLayout{
public MainView() {
Button addButton = new Button(new RouterLink("", CustomerEditor.class));
RouterLink routerLink = new RouterLink("NewPickUp", CustomerEditor.class);
routerLink.getElement().appendChild(addButton.getElement());
this.addToNavbar(routerLink);
}
错误信息
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.apt.lts.view.CustomerEditor': Unsatisfied dependency expressed through field 'customer'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.apt.lts.model.Customer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:305) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at com.vaadin.flow.spring.SpringInstantiator.getOrCreate(SpringInstantiator.java:117) ~[vaadin-spring-12.0.5.jar:na]
at com.vaadin.flow.di.Instantiator.createRouteTarget(Instantiator.java:158) ~[flow-server-2.0.11.jar:2.0.11]
at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.lambda$getRouteTarget(AbstractNavigationStateRenderer.java:127) ~[flow-server-2.0.11.jar:2.0.11]
at java.base/java.util.Optional.orElseGet(Optional.java:369) ~[na:na]
上述错误清楚地表明您正在尝试 Autowired
一个不是 Spring 托管 bean 的 bean(此处为 Customer
)。
这些 bean 以 xml 形式定义,带有标签,或带有一些特殊注释,如 @Bean, @Component, @Service, @Repository
等
简单来说,实体是您需要创建的一些 java 对象,根据您的业务逻辑自行更新和 save/update/remove 它们 in/from 数据库。它们的生命周期无法由 Spring IoC 容器管理。
正如 Debendra Dhinda 在他们的回答中提到的,您的 Customer
class 不是 Spring 组件,因此无法注入。您可以不注入客户,而是在视图的构造函数中创建一个新客户,或者您可以在 @Configuration
class 中添加一个 @Bean
定义方法。这两种方法的共同点是您在某个时候调用 new Customer()
。
// code example for approach 2
@Configuration
public class MySpringConfiguration {
// this method will be called if you inject/autowire a Customer somewhere.
@Bean
public Customer getCustomer(){
return new Customer();
}
}
我正在使用 SpringBoot 以及 JPA 和 Vaadin-flow。我在尝试保存表单数据时遇到此错误。
我尝试在 CustomerRepository class 中添加 @Repository 注解,但仍然无法正常工作。有人可以帮我解决这个问题吗?
Customer.java
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
//Getters ans Setters
}
CustomerEditor.java
@Route(value = "NewPickUp", layout = MainView.class)
@SpringComponent
@UIScope
public class CustomerEditor extends VerticalLayout{
@Autowired
private final CustomerRepository repository;
@Autowired
private Customer customer;
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
Button save = new Button("Save", VaadinIcon.CHECK.create());
Binder<Customer> binder = new Binder<>(Customer.class);
@Autowired
public CustomerEditor(CustomerRepository repository) {
this.repository = repository;
add(firstName, lastName, save );
binder.forField(firstName).bind(Customer::getFirstName, Customer::setFirstName);
binder.forField(lastName).bind(Customer::getLastName, Customer::setLastName);
save.addClickListener(e -> save());
}
void save() {
repository.save(customer);
}
}
CustomerRepository.java
public interface CustomerRepository extends JpaRepository<Customer, Long> {
List<Customer> findByLastNameStartsWithIgnoreCase(String lastName);
}
MainView.java
@Route
public class MainView extends AppLayout{
public MainView() {
Button addButton = new Button(new RouterLink("", CustomerEditor.class));
RouterLink routerLink = new RouterLink("NewPickUp", CustomerEditor.class);
routerLink.getElement().appendChild(addButton.getElement());
this.addToNavbar(routerLink);
}
错误信息
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.apt.lts.view.CustomerEditor': Unsatisfied dependency expressed through field 'customer'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.apt.lts.model.Customer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:305) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at com.vaadin.flow.spring.SpringInstantiator.getOrCreate(SpringInstantiator.java:117) ~[vaadin-spring-12.0.5.jar:na]
at com.vaadin.flow.di.Instantiator.createRouteTarget(Instantiator.java:158) ~[flow-server-2.0.11.jar:2.0.11]
at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.lambda$getRouteTarget(AbstractNavigationStateRenderer.java:127) ~[flow-server-2.0.11.jar:2.0.11]
at java.base/java.util.Optional.orElseGet(Optional.java:369) ~[na:na]
上述错误清楚地表明您正在尝试 Autowired
一个不是 Spring 托管 bean 的 bean(此处为 Customer
)。
这些 bean 以 xml 形式定义,带有标签,或带有一些特殊注释,如 @Bean, @Component, @Service, @Repository
等
简单来说,实体是您需要创建的一些 java 对象,根据您的业务逻辑自行更新和 save/update/remove 它们 in/from 数据库。它们的生命周期无法由 Spring IoC 容器管理。
正如 Debendra Dhinda 在他们的回答中提到的,您的 Customer
class 不是 Spring 组件,因此无法注入。您可以不注入客户,而是在视图的构造函数中创建一个新客户,或者您可以在 @Configuration
class 中添加一个 @Bean
定义方法。这两种方法的共同点是您在某个时候调用 new Customer()
。
// code example for approach 2
@Configuration
public class MySpringConfiguration {
// this method will be called if you inject/autowire a Customer somewhere.
@Bean
public Customer getCustomer(){
return new Customer();
}
}