Spring Boot вызывает метод Rest Controller из службы

Я использую 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 - это bean-компонент? у вас есть какие-нибудь аннотации поверх этого класса?

pvpkiran 10.08.2018 09:36

В QueueListener нет аннотаций.

Benjamin Mwendwa Munyoki 10.08.2018 09:38

Почему QueueListener должен расширяться и зависеть от AuthController? Пожалуйста, пересмотрите организацию ваших зависимостей. Вы действительно хотите внедрить контроллер отдыха в QueueListener? Или вы хотите, чтобы выполнялась какая-то конкретная логика? Вы можете извлечь логику метода addAuthenticatable в службу и внедрить службу для начинающих.

Eirini Graonidou 10.08.2018 09:42

Что это за AuthController implements AuthService and QueueListener extends AuthController again you are injecting AuthController in same class, это правильная реализация?

mallikarjun 10.08.2018 09:42

@EiriniGraonidou Вероятно, мой дизайн ошибочен (я все еще очень зеленый весной - особенно часть аннотаций, что и чем комментировать). Как бы ты это сделал? У меня есть класс, который слушает сообщения от Rabbit и должен вызывать метод контроллера и передавать модель контроллеру для вставки в БД. Часть сообщений и часть БД у меня работают хорошо. Моя проблема заключается в передаче модели контроллеру из класса прослушивания. Как бы ты это сделал? И какие аннотации к каким классам вы бы использовали? Что бы вы сделали Autowire? Мы будем благодарны за вашу помощь.

Benjamin Mwendwa Munyoki 10.08.2018 10:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
5
16 696
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Проблема в том, что ваш класс QueueListener не является компонентом Spring. Следовательно, все переменные, которые у вас есть @Autowired, не будут введены. Сделайте его весенним бином, используя одну из аннотаций, @Service, @Component .....

Например.

@Component
public class QueueListener extends AuthController implements MessageListener{
   .....
}

Нельзя сказать, что это полностью решит вашу проблему (из-за ваших суперклассов), потому что у меня недостаточно информации. Но я уверен, что это избавит от NPE.

ты пробовал отлаживать? когда вы вызываете authController.addAuthenticatable(authModel), authController имеет значение null или нет?

pvpkiran 10.08.2018 10:06

authController имеет значение null

Benjamin Mwendwa Munyoki 10.08.2018 10:09

это означает, что ваш класс не будет сканироваться весной. убедитесь, что у вас есть аннотация @Component, а также убедитесь, что ваш класс просканирован весной. проверить @ComponentScan

pvpkiran 10.08.2018 10:15

Какой класс следует аннотировать с помощью @ComponentScan? Класс прослушивания или AuthController?

Benjamin Mwendwa Munyoki 10.08.2018 10:38

Нет необходимости расширять и autowire этого контроллера. Если вы собираетесь расширять, то нет необходимости помещать зависимости в расширенный класс, это просто усложняет дизайн. Так что либо сделайте контроллер зависимостью, автоматически подключив его, либо расширьте его (в этом случае нет необходимости иметь зависимости). При использовании @Autowired - убедитесь, что все ваши классы правильно аннотированы, как предлагается, и что они сканируются вашим основным классом приложения. В документы рекомендуются некоторые передовые практики.

РЕДАКТИРОВАТЬ Контроллеры снабжены аннотацией @Controller, а классы обслуживания - @Service, который в основном представляет собой декорированную аннотацию @Component. Все это довольно хорошо объяснено в документы, это отличное место для начала исследования.

Вернуться к вопросу:

Если вы все еще получаете NPE, проверьте структуру своего проекта, возможно, ваш класс не подбирается сканированием компонентов Spring или один из классов не помечен. Ваш основной класс (тот, который помечен @SpringBootApplication) должен находиться в корневом пакете / пакете по умолчанию, чтобы сканировать все остальные @Component.

Я не понимаю (весной я все еще зеленый), какие классы и чем аннотировать. Я провел рефакторинг, чтобы удалить расширяющуюся часть, но проблема все еще та же. Как передать данные из класса обслуживания в класс контроллера? Чем я должен аннотировать класс обслуживания и класс контроллера? Какого класса мне следует использовать Autowire и где?

Benjamin Mwendwa Munyoki 10.08.2018 10:46
Ответ принят как подходящий

Я надеюсь, что это не выходит за рамки темы, но в целом то, чего мы хотим достичь, - это своего рода луковичная архитектура. Зависимости должны иметь одно направление.

Ваш контроллер - это точка интеграции вашего приложения. Вы хотите, чтобы 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 дал ответ на ваш вопрос. Но я надеюсь, что это поможет тебе

Другие вопросы по теме