Рубрики
Без рубрики

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

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

Автор оригинала: Eugen Paraschiv.

1. введение

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

В первой статье обсуждалось создание простого клиента для REST API StackExchange. В второй статье мы настроили взаимодействие с Twitter с помощью Spring Social.

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

2. Сервис Tweet Stackexchange

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

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

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

Когда этот вопрос найден, он отправляется в твиттере через шаблон Twitter |, соответствующий этой учетной записи, и очень простой Вопрос объект сохраняется локально. Эта сущность хранит только идентификатор вопроса и учетную запись Twitter, в которой он был отправлен в твиттере.

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

Привязка списка в @RequestParam

Был написан в твиттере в аккаунте Spring Tip .

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

  • идентификатор вопроса – 4596351 в данном случае
  • учетная запись Twitter , на которой был написан вопрос – SpringAtSO
  • сайт Stackexcange , с которого исходит вопрос – Stackoverflow

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

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 twitter account .

Другая операция чирикает вопросы с тегом “bash” – и поскольку такие вопросы на самом деле появляются на нескольких сайтах из сети Stackexchange: StackOverflow , Суперпользователь и AskUbuntu , сначала происходит быстрый процесс выбора одного из этих сайтов, после чего вопрос отправляется в твиттере.

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

4. Настройка

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

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

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

  • идентификаторы вопросов, размещенных в твиттере в каждой учетной записи Twitter, извлекаются и сохраняются в текстовом файле
  • схема базы данных удаляется, и приложение перезапускается – это приведет к повторному созданию схемы и установке всех данных из текстового файла обратно в новую базу данных

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

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

class TweetRowMapper implements RowMapper {
   private Map> accountToQuestions;

   public TweetRowMapper(Map> 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. newArrayList());
      }
      accountToQuestions.get(account).add(questionId);
      return "";
   }
}

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

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

@Test
public void whenQuestionsAreRetrievedFromTheDB_thenNoExceptions() {
   Map> 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 {
    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 stackSitesForTwitterAccount = twitterAccountToStackSites(twitterAccount);
   String site = stackSitesForTwitterAccount.get(0);
   for (String questionId : questionIds) {
      QuestionTweet questionTweet = new QuestionTweet(questionId, twitterAccount, site);
      questionTweetDao.save(questionTweet);
   }
}

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

5. Полный список учетных записей

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

  • SpringTipSpring вопросы из StackOverflow
  • JavaTopSOJava вопросы из StackOverflow
  • RESTDailyREST вопросы из StackOverflow
  • BestJPAJPA вопросы из StackOverflow
  • MavenFactMaven вопросы из StackOverflow
  • BestGitGit вопросы из StackOverflow
  • AskUbuntuBestAskUbuntu лучшие общие вопросы (все темы)
  • ServerFaultBestServerFault лучшие вопросы (все темы)
  • BestBashлучшие вопросы Bash из StackOverflow, ServerFault и AskUbuntu
  • ClojureFact – Вопросы Clojure из StackOverflow
  • ScalaFact – Вопросы Scala из StackOverflow
  • EclipseFacts – Вопросы Eclipse из StackOverflow
  • jQueryDaily – Вопросы jQuery из StackOverflow
  • BestAlgorithms – Вопросы алгоритма из StackOverflow

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

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

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

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