Чириканье вопросов StackExchange с помощью Spring Social

1. Вступление

Это третья и последняя статья о небольшом стороннем проекте - боте, который автоматически отправляет в Твиттере Вопросы с различных сайтов Q & A StackExchange на специализированных учетных записях (полный список в конце статьи).

Ссылка:/tweeting-stackexchange-with-spring-social-part-1/[первая статья]обсуждала создание simple client для StackExchange REST API. В ссылке:/spring social twitter__setup[вторая статья]мы настроили взаимодействие с Twitter с помощью Spring Social.

В этой статье будет описана заключительная часть реализации - часть, отвечающая за взаимодействие между клиентом Stackexchange и TwitterTemplate .

2. Tweet Stackexchange Service

Взаимодействие между клиентом Stackexchange - предоставление необработанных Вопросов и TwitterTemplate - полностью настроенным и способным твитнуть - очень простая услуга - TweetStackexchangeService . API, опубликованный этим:

public void tweetTopQuestionBySite(String site, String twitterAccount){ ... }
public void tweetTopQuestionBySiteAndTag(String site, String twitterAccount, String tag){ ... }

Функциональность проста - эти API будут продолжать читать Вопросы из API Stackexchange REST (через клиента), пока не обнаружится, что не был ранее твитнут для этой конкретной учетной записи.

Когда этот вопрос найден, он отправляется в Твиттере через TwitterTemplate , соответствующий этой учетной записи, и очень простая сущность Question сохраняется локально. Эта сущность хранит только идентификатор вопроса и учетную запись Twitter, на которую он написал в Твиттере.

  • Например ** следующий вопрос:

Hwebted в учетной записи SpringTip .

Сущность Вопрос просто содержит:

  • идентификатор вопроса - 4596351 в данном случае

  • аккаунт в Твиттере, на который был написан вопрос -

SpringAtSO сайт Stackexcange , с которого возникает вопрос -

Переполнение стека

Нам нужно отслеживать эту информацию, чтобы мы знали, какие вопросы уже были написаны в Твиттере, а какие нет.

3. Планировщик

Планировщик использует возможности запланированных задач Spring - они включены через конфигурацию Java:

@Configuration
@EnableScheduling
public class ContextConfig {
  //}

Фактический планировщик относительно прост:

@Component
@Profile(SpringProfileUtil.DEPLOYED)
public class TweetStackexchangeScheduler {

   @Autowired
   private TweetStackexchangeService service;

  //API

   @Scheduled(cron = "0 0 1,5 **  **  ** ")
   public void tweetStackExchangeTopQuestion() throws JsonProcessingException, IOException {
      service.tweetTopQuestionBySiteAndTag("StackOverflow", Tag.clojure.name(), "BestClojure", 1);
      String randomSite = StackexchangeUtil.pickOne("SuperUser", "StackOverflow");
      service.tweetTopQuestionBySiteAndTag(randomSite, Tag.bash.name(), "BestBash", 1);
   }
}

Выше были настроены две операции твита - один твит из вопросов StackOverflow, которые помечены как «clojure» в твиттере Best Of Clojure .

Другая операция отправляет в Твиттере вопросы, помеченные как «bash», и потому, что такие вопросы действительно появляются на нескольких сайтах из сети Stackexchange:

StackOverflow , SuperUser и AskUbuntu Сначала идет быстрый процесс выбора одного из этих сайтов, после чего вопрос пишется в Твиттере.

Наконец, задание cron планируется запускать в 1:00 и 5:00 каждый день.

4. Настроить

Это был проект для домашних животных, он начинался с очень простой структуры базы данных - теперь это все еще просто, но это было еще больше. Поэтому одной из основных целей было иметь возможность легко изменить структуру базы данных - конечно, есть several инструменты для миграции баз данных, но все они излишни для такой простой проект.

Поэтому я решил сохранить данные настройки в a простой текстовый формат - который будет обновляться полуавтоматически.

Настройка состоит из двух основных шагов:

  • идентифицированы идентификаторы вопросов, написанных в твиттере на каждом аккаунте в твиттере

и хранится в текстовом файле ** схема базы данных удаляется и приложение перезапускается - это

создаст схему снова и настроит все данные из текстового файла обратно в новую базу данных

4.1. Исходные данные настройки

Процесс извлечения данных из существующей базы данных достаточно прост с JDBC; Сначала мы определим RowMapper:

class TweetRowMapper implements RowMapper<String> {
   private Map<String, List<Long>> accountToQuestions;

   public TweetRowMapper(Map<String, List<Long>> accountToQuestions) {
      super();
      this.accountToQuestions = accountToQuestions;
   }

   public String mapRow(ResultSet rs, int line) throws SQLException {
      String questionIdAsString = rs.getString("question__id");
      long questionId = Long.parseLong(questionIdAsString);
      String account = rs.getString("account");

      if (accountToQuestions.get(account) == null) {
         accountToQuestions.put(account, Lists.<Long> newArrayList());
      }
      accountToQuestions.get(account).add(questionId);
      return "";
   }
}

Это создаст список вопросов для каждой учетной записи Twitter.

Далее мы собираемся использовать это в простом тесте:

@Test
public void whenQuestionsAreRetrievedFromTheDB__thenNoExceptions() {
   Map<String, List<Long>> accountToQuestionsMap = Maps.newHashMap();
   jdbcTemplate.query
      ("SELECT **  FROM question__tweet;", new TweetRowMapper(accountToQuestionsMap));

   for (String accountName : accountToQuestionsMap.keySet()) {
      System.out.println
         (accountName + "=" + valuesAsCsv(accountToQuestionsMap.get(accountName)));
   }
}

После получения Вопросов для учетной записи, тест просто перечислит их; например:

SpringAtSO=3652090,1079114,5908466,...

4.2. Восстановление данных настройки

Строки данных, сгенерированные на предыдущем шаге, хранятся в a setup.properties file , который доступен для Spring :

@Configuration
@PropertySource({ "classpath:setup.properties" })
public class PersistenceJPAConfig {
  //}

Когда приложение запускается, процесс установки выполняется. Этот простой процесс использует Spring ApplicationListener, прослушивающий ContextRefreshedEvent :

@Component
public class StackexchangeSetup implements ApplicationListener<ContextRefreshedEvent> {
    private boolean setupDone;

    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (!setupDone) {
            recreateAllQuestionsOnAllTwitterAccounts();
            setupDone = true;
        }
    }
}

Наконец, вопросы извлекаются из файла setup.properties и воссоздаются:

private void recreateAllQuestionsOnTwitterAccount(String twitterAccount) {
   String tweetedQuestions = env.getProperty(twitterAccount.name();
   String[]questionIds = tweetedQuestions.split(",");
   recreateQuestions(questionIds, twitterAccount);
}
void recreateQuestions(String[]questionIds, String twitterAccount) {
   List<String> stackSitesForTwitterAccount = twitterAccountToStackSites(twitterAccount);
   String site = stackSitesForTwitterAccount.get(0);
   for (String questionId : questionIds) {
      QuestionTweet questionTweet = new QuestionTweet(questionId, twitterAccount, site);
      questionTweetDao.save(questionTweet);
   }
}

Этот простой процесс позволяет легко обновлять структуру БД - поскольку данные полностью стираются и полностью восстанавливаются, нет никакой необходимости в какой-либо реальной миграции ** .

5. Полный список счетов

  • Полный список учетных записей Twitter ** :

  • SpringTip - Spring вопросы от

Переполнение стека JavaTopSO - Java ** вопросы от

Переполнение стека RESTDaily - REST ** вопросы от

Переполнение стека BestJPA - JPA ** вопросы от

Переполнение стека MavenFact - Maven ** вопросы от

Переполнение стека BestGit - Git ** вопросы от

Переполнение стека AskUbuntuBest - AskUbuntu ** best

общие вопросы (все темы) ServerFaultBest - ServerFault **

лучшие вопросы (все темы) BestBash - лучшие вопросы Bash ** от

StackOverflow, ServerFault и AskUbuntu ** ClojureFact - Clojure вопросы от

Переполнение стека ** ScalaFact - вопросы по Scala от

Переполнение стека ** EclipseFacts - вопросы по Eclipse

от StackOverflow ** jQueryDaily - вопросы по jQuery от

Переполнение стека ** BestAlgorithms - Алгоритм

вопросы от StackOverflow

В каждой из этих учетных записей создается 2 твита в день с вопросами с самым высоким рейтингом по конкретной теме.

6. Заключение

Эта третья статья завершает серию об интеграции со StackOverflow и другими сайтами StackExchange для получения вопросов через их REST API, а также об интеграции с Twitter и Spring Social, чтобы опубликовать эти вопросы. Потенциальное направление, которое стоит изучить, делает то же самое с Google Plus - возможно, с использованием страниц, а не учетных записей.

  • 14 учетных записей Twitter ** запущены и работают в результате этого проекта - фокусируются на различных темах и производят низкообъемный и, надеюсь, высококачественный контент (идеи для других тегов, которые заслуживают своей собственной учетной записи Twitter, приветствуются в комментариях).