Я использую 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);
}
}
}
Ошибка возникает, когда я вызываю метод addAuthenticatable (), который находится в AuthController. Любая помощь будет оценена по достоинству.
В QueueListener нет аннотаций.
Почему QueueListener должен расширяться и зависеть от AuthController? Пожалуйста, пересмотрите организацию ваших зависимостей. Вы действительно хотите внедрить контроллер отдыха в QueueListener? Или вы хотите, чтобы выполнялась какая-то конкретная логика? Вы можете извлечь логику метода addAuthenticatable в службу и внедрить службу для начинающих.
Что это за AuthController implements AuthService and QueueListener extends AuthController again you are injecting AuthController in same class, это правильная реализация?
@EiriniGraonidou Вероятно, мой дизайн ошибочен (я все еще очень зеленый весной - особенно часть аннотаций, что и чем комментировать). Как бы ты это сделал? У меня есть класс, который слушает сообщения от Rabbit и должен вызывать метод контроллера и передавать модель контроллеру для вставки в БД. Часть сообщений и часть БД у меня работают хорошо. Моя проблема заключается в передаче модели контроллеру из класса прослушивания. Как бы ты это сделал? И какие аннотации к каким классам вы бы использовали? Что бы вы сделали Autowire? Мы будем благодарны за вашу помощь.




Проблема в том, что ваш класс QueueListener не является компонентом Spring. Следовательно, все переменные, которые у вас есть @Autowired, не будут введены. Сделайте его весенним бином, используя одну из аннотаций, @Service, @Component .....
Например.
@Component
public class QueueListener extends AuthController implements MessageListener{
.....
}
Нельзя сказать, что это полностью решит вашу проблему (из-за ваших суперклассов), потому что у меня недостаточно информации. Но я уверен, что это избавит от NPE.
ты пробовал отлаживать? когда вы вызываете authController.addAuthenticatable(authModel), authController имеет значение null или нет?
authController имеет значение null
это означает, что ваш класс не будет сканироваться весной. убедитесь, что у вас есть аннотация @Component, а также убедитесь, что ваш класс просканирован весной. проверить @ComponentScan
Какой класс следует аннотировать с помощью @ComponentScan? Класс прослушивания или AuthController?
Нет необходимости расширять и autowire этого контроллера. Если вы собираетесь расширять, то нет необходимости помещать зависимости в расширенный класс, это просто усложняет дизайн. Так что либо сделайте контроллер зависимостью, автоматически подключив его, либо расширьте его (в этом случае нет необходимости иметь зависимости).
При использовании @Autowired - убедитесь, что все ваши классы правильно аннотированы, как предлагается, и что они сканируются вашим основным классом приложения. В документы рекомендуются некоторые передовые практики.
РЕДАКТИРОВАТЬ
Контроллеры снабжены аннотацией @Controller, а классы обслуживания - @Service, который в основном представляет собой декорированную аннотацию @Component. Все это довольно хорошо объяснено в документы, это отличное место для начала исследования.
Вернуться к вопросу:
Если вы все еще получаете NPE, проверьте структуру своего проекта, возможно, ваш класс не подбирается сканированием компонентов Spring или один из классов не помечен. Ваш основной класс (тот, который помечен @SpringBootApplication) должен находиться в корневом пакете / пакете по умолчанию, чтобы сканировать все остальные @Component.
Я не понимаю (весной я все еще зеленый), какие классы и чем аннотировать. Я провел рефакторинг, чтобы удалить расширяющуюся часть, но проблема все еще та же. Как передать данные из класса обслуживания в класс контроллера? Чем я должен аннотировать класс обслуживания и класс контроллера? Какого класса мне следует использовать Autowire и где?
Я надеюсь, что это не выходит за рамки темы, но в целом то, чего мы хотим достичь, - это своего рода луковичная архитектура. Зависимости должны иметь одно направление.
Ваш контроллер - это точка интеграции вашего приложения. Вы хотите, чтобы 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 дал ответ на ваш вопрос. Но я надеюсь, что это поможет тебе
QueueListener - это bean-компонент? у вас есть какие-нибудь аннотации поверх этого класса?