如何在 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
我买了这本新书来尝试学习Spring快速启动。开始很顺利,我轻松创建了一个 REST API。但是后来我们添加了 CrudRepository,我发现书中描述的代码存在问题。此外,没有可供下载的代码,因为作者将其从 Oreily 的 git 存储库中删除以修复某些问题...
问题是,如果我尝试按照书中描述的方式构建代码(没有默认构造函数),我会收到 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> {
}
这里是主要的 class -- 对塞在底部的 class 表示歉意。
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;
}
}
CoffeeRepository 接口缺少@Repository 注解。
更新:
- 在 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 class 标记为一个 bean,因此组件扫描机制可以将其拾取并将其拉入应用程序上下文。由于 @Repository 是 @Component 的特化,它还可以让带注释的 classes 被发现并注册到应用程序上下文中。
我买了这本新书来尝试学习Spring快速启动。开始很顺利,我轻松创建了一个 REST API。但是后来我们添加了 CrudRepository,我发现书中描述的代码存在问题。此外,没有可供下载的代码,因为作者将其从 Oreily 的 git 存储库中删除以修复某些问题...
问题是,如果我尝试按照书中描述的方式构建代码(没有默认构造函数),我会收到 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> {
}
这里是主要的 class -- 对塞在底部的 class 表示歉意。
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;
}
}
CoffeeRepository 接口缺少@Repository 注解。
更新:
- 在 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 class 标记为一个 bean,因此组件扫描机制可以将其拾取并将其拉入应用程序上下文。由于 @Repository 是 @Component 的特化,它还可以让带注释的 classes 被发现并注册到应用程序上下文中。