如何在 Spring Boot 的 @RestController 注释用于创建请求处理程序的方法中使用带有参数的构造函数

Posted

技术标签:

【中文标题】如何在 Spring Boot 的 @RestController 注释用于创建请求处理程序的方法中使用带有参数的构造函数【英文标题】:How to us a constructor with parameters in a method used by Spring Boot's @RestController annotation to create a request handler 【发布时间】:2021-06-17 22:55:57 【问题描述】:

我买这本新书是为了快速学习 Spring Boot。开始的时候很好,我很容易创建了一个 REST API。但后来我们添加了 CrudRepository,我发现书中描述的代码存在问题。另外,没有代码可供下载,因为作者从 Oreily 的 git repo 中删除了它以修复一些问题...

问题是,如果我尝试按照书中描述的方式构建代码(没有默认构造函数),我会收到一个 Java 错误,抱怨没有默认构造函数。如果我添加一个默认构造函数,它会构建,但是 Spring 使用它而不是新的构造函数,这需要传递一个参数。因此,当我实际调用 API 时,例如调用 /coffees 端点时,我得到一个 java.lang.NullPointerException: null

那么 Spring 应该如何知道要使用哪个构造函数,以及它如何为这个参数传递值?

这里是控制器:

package com.bw.restdemo;

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

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/coffees")
class RestAPIDemoController 
    private final CoffeeRepository coffeeRepository;
    
    public RestAPIDemoController(CoffeeRepository coffeeRepository) 
        this.coffeeRepository = coffeeRepository;
        
        this.coffeeRepository.saveAll(List.of(
                new Coffee("Cafe Cereza"),
                new Coffee("Freedom Fuel"),
                new Coffee("Cold Brew"),
                new Coffee("Sumatra")
                ));
    
    public RestAPIDemoController() 
        this.coffeeRepository = null; 
    ; 
    
    //@RequestMapping(value = "/coffees", method = RequestMethod.GET)
    @GetMapping
    Iterable<Coffee> getCoffees() 
        return coffeeRepository.findAll();
    
    
    @GetMapping("/id")
    Optional<Coffee> getCoffeeById(@PathVariable String id) 
        return coffeeRepository.findById(id); 
    
    
    @PostMapping
    Coffee postCoffee(@RequestBody Coffee coffee) 
        return coffeeRepository.save(coffee); 
    
    
    @PutMapping("/id")
    ResponseEntity<Coffee> putCoffee(@PathVariable String id, @RequestBody Coffee coffee) 
        return (!coffeeRepository.existsById(id)) 
                ? new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.CREATED) 
                : new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);
    
    
    @DeleteMapping("/id")
    void deleteCoffee(@PathVariable String id) 
        coffeeRepository.deleteById(id); 
    

这里是我定义接口的地方:

package com.bw.restdemo;

import org.springframework.data.repository.CrudRepository;

interface CoffeeRepository extends CrudRepository<Coffee, String> 
    

这里是主要课程——为塞在底部的课程道歉。

package com.bw.restdemo;

import java.util.UUID;

import javax.persistence.Entity;
import javax.persistence.Id;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RestDemoApplication 

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



@Entity
class Coffee 
    @Id
    private String id;
    private String name;
    
    public Coffee(String id, String name) 
        this.id = id;
        this.name = name;
    
    public void setId(String id) 
        this.id = id; 
    
    
    public Coffee(String name) 
        this(UUID.randomUUID().toString(), name); 
    
    public String getId() 
        return id; 
    
    public String getName() 
        return name; 
    
    public void setName(String name) 
        this.name = name; 
    

【问题讨论】:

【参考方案1】:

CoffeeRepository 接口缺少@Repository Annotation。

更新:

在 CoffeeRepository 中添加 @Repository 注释 从 RestAPIDemoController 中移除默认构造函数。
package com.bw.restdemo;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
interface CoffeeRepository extends CrudRepository<Coffee, String> 
    

解释

在 Spring 框架中,@Component 注解将 java 类标记为 bean,因此组件扫描机制可以将其拾取并将其拉入应用程序上下文。由于 @Repository 是 @Component 的一个特化,它还可以发现带注释的类并将其注册到应用程序上下文中。

更多信息请访问HowToDoInJava - @Repository annotation in Spring Boot

【讨论】:

以上是关于如何在 Spring Boot 的 @RestController 注释用于创建请求处理程序的方法中使用带有参数的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot:Spring Boot 如何测试打包部署

如何在 spring-boot 中禁用 spring-data-mongodb 自动配置

spring boot学习02如何在spring boot项目中访问jsp

如何在 spring-boot 中替换最新的 Jetty 9?

如何在 spring-boot 中配置 Jetty(很容易?)

如何在不从 spring-boot-starter-web 继承的情况下在 Spring Boot 中获取 ObjectMapper 实例?