Spring 引导从服务调用 Rest Controller 方法
Spring Boot call a Rest Controller method from a service
我正在使用 Spring Boot 从服务调用休息控制器方法。调用该方法时,我收到错误 java.lang.NullPointerException 广泛的情况是,我的服务从 RabbitMQ 队列接收有效负载并提取有效负载的内容,然后将其传递给控制器以保存到数据库中。队列部分有效(我可以从队列中接收消息并提取内容)。数据库部分也有效。问题是从服务调用控制器方法。
这是我的休息控制器
@RestController
@RequestMapping("/auth")
public class AuthController implements AuthService {
@Autowired
RabbitTemplate rabbitTemplate;
@Autowired
AuthRepository authRepository;
public AuthModel addAuthenticatable(AuthModel auth){
auth.setCreatedAt(DateTimeUtility.getDateTime());
return authRepository.save(auth);
}
}
我的服务代码:
public class QueueListener extends AuthController implements MessageListener{
private String identifier;
private JSONArray globalObject;
private int userId;
private String pin;
@Autowired
AuthController authController;
@Override
public void onMessage(Message message) {
String msg = new String(message.getBody());
String output = msg.replaceAll("\\", "");
String jsonified = output.substring(1, output.length()-1);
JSONArray obj = new JSONArray(jsonified);
this.globalObject = obj;
this.identifier = obj.getJSONObject(0).getString("identifier");
resolveMessage();
}
public void resolveMessage() {
if(identifier.equalsIgnoreCase("ADD_TO_AUTH")) {
for(int i = 0; i < globalObject.length(); i++){
JSONObject o = globalObject.getJSONObject(i);
this.userId = Integer.parseInt(o.getString("userId"));
this.pin = o.getString("pin");
}
AuthModel authModel = new AuthModel();
authModel.setUserId(userId);
authModel.setPin(pin);
authController.addAuthenticatable(authModel);
}
}
}
调用AuthController中的addAuthenticatable()方法时出现错误。任何帮助将不胜感激。
问题是您的 class QueueListener 不是 spring bean。因此,您拥有 @Autowired
的所有变量都不会被注入。使用注解@Service
、@Component
.....
之一使其成为 spring bean
例如。
@Component
public class QueueListener extends AuthController implements MessageListener{
.....
}
不能说这会完全解决您的问题(因为您的超级 classes),因为我没有足够的信息。但我相信它会摆脱 NPE。
无需扩展 和 自动装配该控制器。如果要扩展,则无需将依赖项放在扩展 class 中,这只会使设计复杂化。因此,要么通过自动装配使控制器成为依赖项,要么扩展它(在这种情况下,它不需要具有依赖项)。
使用 @Autowired
时 - 确保所有 class 都按照建议正确注释,并且它们正在被您的主应用程序 class 扫描。 docs.
中推荐了一些好的做法
编辑
控制器用 @Controller
注释,服务 class 用 @Service
注释,这基本上是一个修饰的 @Component
注释。所有这些在 docs 中都有很好的解释,这是开始探索的好地方。
回到问题:
如果您仍然遇到 NPE,请检查您的项目结构,可能您的 class 没有被 spring 的组件扫描或 classes 之一选中没有注释。您的主要 class(用 @SpringBootApplication
注释的那个)应该在 root/default 包中,以便扫描所有其他 @Component
。
我希望这不会超出主题,但通常我们想要实现的是一种洋葱架构。依赖关系应该有一个方向。
您的控制器是您应用程序的集成点。您希望每个 REST 触发某些逻辑片段的执行。您的控制器不应扩展 类 或实现与业务逻辑有关的接口。这部分属于另一层。
一切关于逻辑的东西都属于服务:
@Service
public class AuthService {
@Autowired
private AuthRepository authRepository;
private String attribute;
public boolean isAuthenticated(String username) {
authRepository.doSomething();
//implementation of the logic to check if a user is authenticated.
}
public boolean authenticate(String username, char[] password) {
// implementation of logic to authenticate.
authRepository.authenticate();
}
public AuthModel save(AuthModel model) {
//implementation of saving the model
}
}
在服务层提取您的逻辑,使事情可重用。
现在您可以将服务注入 controller
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthService authService;
public AuthModel addAuthenticatable(AuthModel auth){
//process input etc..
return authService.save(auth);
}
}
或 amqListener
@Component
public class QueueListener implements MessageListener {
@Autowired
private AuthService authService;
@Autowired
private SomeOtherService otherService;
@Override
public void onMessage(Message message) {
JSONArray array = processInput();
JSONArray obj = new JSONArray(jsonified);
String identifier = obj.getJSONObject(0).getString("identifier");
// extract the business logic to the service layer. Don't mix layer responsibilities
otherService.doYourThing(obj, identifier);
resolveMessage();
}
private JSONArray processInput(Message message) {
String msg = new String(message.getBody());
String output = msg.replaceAll("\\", "");
String jsonified = output.substring(1, output.length()-1);
}
和你的配置,这样你就可以让 spring 知道在哪里寻找带注释的 类。
@Configuration
@ComponentScan({"your.service.packages"})
@EntityScan(basePackages = "your.model.package")
@EnableJpaRepositories("your.repository.packages")
@EnableRabbit // probaby
@EnableWebMvc // probably
public class Config {
//you could also define other beans here
@Bean
public SomeBean someBean() {
return new SomeBean();
}
}
@pvpkiran 给出了您实际问题的答案。但我希望这对你有帮助
我正在使用 Spring Boot 从服务调用休息控制器方法。调用该方法时,我收到错误 java.lang.NullPointerException 广泛的情况是,我的服务从 RabbitMQ 队列接收有效负载并提取有效负载的内容,然后将其传递给控制器以保存到数据库中。队列部分有效(我可以从队列中接收消息并提取内容)。数据库部分也有效。问题是从服务调用控制器方法。
这是我的休息控制器
@RestController
@RequestMapping("/auth")
public class AuthController implements AuthService {
@Autowired
RabbitTemplate rabbitTemplate;
@Autowired
AuthRepository authRepository;
public AuthModel addAuthenticatable(AuthModel auth){
auth.setCreatedAt(DateTimeUtility.getDateTime());
return authRepository.save(auth);
}
}
我的服务代码:
public class QueueListener extends AuthController implements MessageListener{
private String identifier;
private JSONArray globalObject;
private int userId;
private String pin;
@Autowired
AuthController authController;
@Override
public void onMessage(Message message) {
String msg = new String(message.getBody());
String output = msg.replaceAll("\\", "");
String jsonified = output.substring(1, output.length()-1);
JSONArray obj = new JSONArray(jsonified);
this.globalObject = obj;
this.identifier = obj.getJSONObject(0).getString("identifier");
resolveMessage();
}
public void resolveMessage() {
if(identifier.equalsIgnoreCase("ADD_TO_AUTH")) {
for(int i = 0; i < globalObject.length(); i++){
JSONObject o = globalObject.getJSONObject(i);
this.userId = Integer.parseInt(o.getString("userId"));
this.pin = o.getString("pin");
}
AuthModel authModel = new AuthModel();
authModel.setUserId(userId);
authModel.setPin(pin);
authController.addAuthenticatable(authModel);
}
}
}
调用AuthController中的addAuthenticatable()方法时出现错误。任何帮助将不胜感激。
问题是您的 class QueueListener 不是 spring bean。因此,您拥有 @Autowired
的所有变量都不会被注入。使用注解@Service
、@Component
.....
例如。
@Component
public class QueueListener extends AuthController implements MessageListener{
.....
}
不能说这会完全解决您的问题(因为您的超级 classes),因为我没有足够的信息。但我相信它会摆脱 NPE。
无需扩展 和 自动装配该控制器。如果要扩展,则无需将依赖项放在扩展 class 中,这只会使设计复杂化。因此,要么通过自动装配使控制器成为依赖项,要么扩展它(在这种情况下,它不需要具有依赖项)。
使用 @Autowired
时 - 确保所有 class 都按照建议正确注释,并且它们正在被您的主应用程序 class 扫描。 docs.
编辑
控制器用 @Controller
注释,服务 class 用 @Service
注释,这基本上是一个修饰的 @Component
注释。所有这些在 docs 中都有很好的解释,这是开始探索的好地方。
回到问题:
如果您仍然遇到 NPE,请检查您的项目结构,可能您的 class 没有被 spring 的组件扫描或 classes 之一选中没有注释。您的主要 class(用 @SpringBootApplication
注释的那个)应该在 root/default 包中,以便扫描所有其他 @Component
。
我希望这不会超出主题,但通常我们想要实现的是一种洋葱架构。依赖关系应该有一个方向。
您的控制器是您应用程序的集成点。您希望每个 REST 触发某些逻辑片段的执行。您的控制器不应扩展 类 或实现与业务逻辑有关的接口。这部分属于另一层。
一切关于逻辑的东西都属于服务:
@Service
public class AuthService {
@Autowired
private AuthRepository authRepository;
private String attribute;
public boolean isAuthenticated(String username) {
authRepository.doSomething();
//implementation of the logic to check if a user is authenticated.
}
public boolean authenticate(String username, char[] password) {
// implementation of logic to authenticate.
authRepository.authenticate();
}
public AuthModel save(AuthModel model) {
//implementation of saving the model
}
}
在服务层提取您的逻辑,使事情可重用。
现在您可以将服务注入 controller
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthService authService;
public AuthModel addAuthenticatable(AuthModel auth){
//process input etc..
return authService.save(auth);
}
}
或 amqListener
@Component
public class QueueListener implements MessageListener {
@Autowired
private AuthService authService;
@Autowired
private SomeOtherService otherService;
@Override
public void onMessage(Message message) {
JSONArray array = processInput();
JSONArray obj = new JSONArray(jsonified);
String identifier = obj.getJSONObject(0).getString("identifier");
// extract the business logic to the service layer. Don't mix layer responsibilities
otherService.doYourThing(obj, identifier);
resolveMessage();
}
private JSONArray processInput(Message message) {
String msg = new String(message.getBody());
String output = msg.replaceAll("\\", "");
String jsonified = output.substring(1, output.length()-1);
}
和你的配置,这样你就可以让 spring 知道在哪里寻找带注释的 类。
@Configuration
@ComponentScan({"your.service.packages"})
@EntityScan(basePackages = "your.model.package")
@EnableJpaRepositories("your.repository.packages")
@EnableRabbit // probaby
@EnableWebMvc // probably
public class Config {
//you could also define other beans here
@Bean
public SomeBean someBean() {
return new SomeBean();
}
}
@pvpkiran 给出了您实际问题的答案。但我希望这对你有帮助