将接口传递给控制器​​构造函数的问题

Issue with Passing Interface to controller Constructor

我是 Spring 的新手。以下是我面临的问题。请帮忙。

启动开发工具时出现以下错误

tacos.web.DesignTacoController 中构造函数的参数 0 需要找不到类型 'taco.data.IngredientRepository' 的 bean。

操作:

考虑在您的配置中定义类型为 'taco.data.IngredientRepository' 的 bean。

IngredientRepository.java

package taco.data;

import tacos.Ingredient;

public interface IngredientRepository {

    Iterable<Ingredient> findAll();

    Ingredient findOne(String id);

    Ingredient save(Ingredient ingredient);

}

JdbcIngredientRepository.java

package taco.data;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import tacos.Ingredient;

@Repository
public class JdbcIngredientRepository implements IngredientRepository {


    private JdbcTemplate jdbc;

    @Autowired
    public JdbcIngredientRepository (JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    @Override
    public Iterable<Ingredient> findAll() {
        return jdbc.query("SELECT ID, NAME, TYPE FROM INGREDIENT", this::mapRowToIngredient);
    }

    @Override
    public Ingredient findOne(String id) {
        return jdbc.queryForObject("SELECT ID, NAME, TYPE FROM INGREDIENT WHERE ID=?", this::mapRowToIngredient, id);
    }

    @Override
    public Ingredient save(Ingredient ingredient) {
        jdbc.update("INSERT INTO INGREDIENT VALUES (?,?,?)", ingredient.getId(), ingredient.getId(), ingredient.getType());
        return ingredient;
    }

    private Ingredient mapRowToIngredient(ResultSet rs, int rowNum)
            throws SQLException {
        return new Ingredient(rs.getString("id"), rs.getString("name"), Ingredient.Type.valueOf(rs.getString("type")));
    }

}

DesignTacoController.java

package tacos.web;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import lombok.extern.slf4j.Slf4j;
import taco.data.IngredientRepository;
import tacos.Ingredient;
import tacos.Ingredient.Type;
import tacos.Taco;

@Slf4j
@Controller
@RequestMapping("/design")
@SessionAttributes("order")
public class DesignTacoController {

    private final IngredientRepository ingredientRepo;

    @Autowired
    public DesignTacoController(IngredientRepository ingredientRepo) {
        this.ingredientRepo = ingredientRepo;
    }

    @GetMapping
    public String showDesignForm(Model model) {


        List<Ingredient> ingredients = new ArrayList<>();
        ingredientRepo.findAll().forEach(i -> ingredients.add(i));

        Type[] types = Ingredient.Type.values();
        for (Type type : types) {
            model.addAttribute(type.toString().toLowerCase(),
            filterByType(ingredients, type));
        }
        model.addAttribute("design", new Taco());
        return "design";

    }

    @PostMapping
    public String processDesign(@Valid Taco design, Errors errors) {
        if(errors.hasErrors()) {
            return "design";
        }

        log.info("Processing Design " + design);

        return "redirect:/orders/current";
    }

    public List<Ingredient> filterByType (List<Ingredient> actualList, Type type) {
        return actualList.stream().filter(ingredient -> type.equals(ingredient.getType())).collect(Collectors.toList());
    }
}

Spring开机BootstrapClass

package tacos;

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

@SpringBootApplication
public class TacoCloudApplication {

    public static void main(String[] args) {
        SpringApplication.run(TacoCloudApplication.class, args);
    }

}

Github Project Link

问题

TacoCloudApplication 没有看到任何 @Component@Repository 是一个 @Component)在 tacos 包之外定义。

来自 Spring Boot Reference Guide:

A single @SpringBootApplication annotation can be used to enable those three features, that is:

  • @EnableAutoConfiguration: enable Spring Boot’s auto-configuration mechanism
  • @ComponentScan: enable @Component scan on the package where the application is located
  • @Configuration: allow to register extra beans in the context or import additional configuration classes

它只看到 tacos 包下定义的 @Components

解决方案

JdbcIngredientRepository 移动到以 tacos 开头的包。

这样你的申请结构就变成了:

└── tacos
    ├── data
    │   ├── IngredientRepository.java
    │   └── JdbcIngredientRepository.java
    ├── Ingredient.java
    ├── Order.java
    ├── TacoCloudApplication.java
    ├── Taco.java
    └── web
    ├── DesignTacoController.java
    ├── OrderController.java
    └── WebConfig.java

或添加

@ComponentScans(
    value = {
        @ComponentScan("tacos"),
        @ComponentScan("taco")
    }
)

TacoCloudApplicationclass.

另请参阅: