Tweeten von StackExchange-Fragen mit Spring Social

1. Einführung

Dies ist der dritte und letzte Artikel über ein kleines Nebenprojekt - ein Bot, der automatisch Fragen von verschiedenen Stack & Exchange-Websites für Fragen und Antworten zu speziellen Konten twittert (vollständige Liste am Ende des Artikels).

Der Link:/tweeting-stackexchange-with-spring-social-part-1/[erster Artikel]befasste sich mit dem Erstellen eines simple client für die StackExchange-REST-API. Im Link:/spring social twitter__setup[zweiter Artikel]haben wir die Interaktion mit Twitter mithilfe von Spring Social eingerichtet.

In diesem Artikel wird der letzte Teil der Implementierung beschrieben - der verantwortliche Teil für die Interaktion zwischen dem Stackexchange-Client und der TwitterTemplate .

2. Der Tweet Stackexchange Service

Die Interaktion zwischen dem Stackexchange Client - der die rohen Fragen offenlegt - und dem TwitterTemplate - vollständig eingerichtet und in der Lage zu tweeten - ist ein sehr einfacher Dienst - der TweetStackexchangeService . Die hier veröffentlichte API lautet:

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

Die Funktionalität ist einfach: Diese APIs lesen immer wieder Fragen aus der Stackexchange-REST-API (über den Client), bis festgestellt wird, dass vor diesem Konto noch nicht getwittert wurde.

Wenn diese Frage gefunden wird, wird sie über das diesem Konto entsprechende TwitterTemplate ** getwittert, und eine sehr einfache Question -Entität wird lokal gespeichert. Diese Entität speichert nur die ID der Frage und des Twitter-Kontos, auf dem sie getwittert wurde.

  • Zum Beispiel ** folgende Frage:

Die Entität Frage enthält einfach:

  • die ID der Frage - 4596351 in diesem Fall

  • das Twitter-Konto , auf dem die Frage getwittert wurde -

SpringAtSO die Stackexcange Site ** , von der die Frage stammt -

Paketüberfluss

Wir müssen diese Informationen nachverfolgen, damit wir wissen, welche Fragen bereits getwittert wurden und welche nicht.

3. Der Scheduler

Der Scheduler nutzt die geplanten Task-Funktionen von Spring - diese werden über die Java-Konfiguration aktiviert:

@Configuration
@EnableScheduling
public class ContextConfig {
  //}

Der eigentliche Scheduler ist relativ einfach:

@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);
   }
}

Es gibt zwei oben konfigurierte Tweet-Operationen - ein Tweets aus StackOverflow-Fragen, die auf dem https://twitter.com/ClojureFact [Best Of Clojure-Twitter-Konto mit „clojure“ gekennzeichnet sind.

Die andere Operation twittert Fragen, die mit „bash“ gekennzeichnet sind - und da diese Fragen tatsächlich auf mehreren Websites des Stackexchange-Netzwerks angezeigt werden:

StackOverflow , SuperUser und AskUbuntu Zunächst erfolgt eine schnelle Auswahl, um eine dieser Websites auszuwählen. Anschließend wird die Frage getwittert.

Schließlich wird der cron-Job täglich um 1 Uhr und 5 Uhr morgens ausgeführt.

4. Konfiguration

Da es sich um ein Haustierprojekt handelt, begann es mit einer sehr einfachen Datenbankstruktur - es ist immer noch einfach, aber es war noch viel mehr. Eines der Hauptziele bestand daher darin, die Datenbankstruktur leicht ändern zu können - natürlich gibt es für Datenbankmigrationen natürlich several tools so ein einfaches Projekt.

Also beschloss ich, die Einstellungsdaten im https://github.com/eugenp/stackexchange2twitter/blob/master/src/main/resources/setup.properties (einem einfachen Textformat) beizubehalten.

Das Setup besteht aus zwei Hauptschritten:

  • Die IDs der Fragen, die auf jedem Twitter-Account getwittert wurden, werden abgerufen

und in einer Textdatei gespeichert ** Das Datenbankschema wird gelöscht und die Anwendung neu gestartet - dies

erstellt das Schema erneut und setzt alle Daten aus der Textdatei in die neue Datenbank zurück

4.1. Die Rohdaten zum Setup

Das Abrufen der Daten aus der vorhandenen Datenbank ist mit JDBC einfach genug. Zuerst definieren wir einen 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 "";
   }
}

Dadurch wird eine Liste mit Fragen für jeden Twitter-Account erstellt.

Als Nächstes werden wir dies in einem einfachen Test verwenden:

@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)));
   }
}

Nachdem Sie die Fragen für ein Konto abgerufen haben, listet der Test sie einfach auf. zum Beispiel:

SpringAtSO=3652090,1079114,5908466,...

4.2. Wiederherstellen der Setup-Daten

Die durch den vorherigen Schritt erzeugten Datenzeilen werden in der Datei a setup.properties gespeichert, die Spring zur Verfügung gestellt wird :

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

Wenn die Anwendung gestartet wird, wird der Setup-Vorgang ausgeführt. Dieser einfache Prozess verwendet einen Spring ApplicationListener, der ein ContextRefreshedEvent überwacht:

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

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

Schließlich werden die Fragen aus der Datei setup.properties abgerufen und erneut erstellt:

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);
   }
}

Dieser einfache Vorgang ermöglicht ein einfaches Aktualisieren der DB-Struktur. Da die Daten vollständig gelöscht und vollständig neu erstellt werden, ist keine eigentliche Migration erforderlich.

5. Vollständige Liste der Konten

Die vollständige Liste der Twitter-Konten lautet:

Paketüberfluss JavaTopSO - Java ** Fragen von

Paketüberfluss RESTDaily - REST ** Fragen von

Paketüberfluss MavenFact - Maven ** Fragen von

Paketüberfluss BestGit - Git ** -Fragen von

Paketüberfluss AskUbuntuBest AskUbuntu

allgemeine Fragen (alle Themen) ServerFaultBest - ServerFault **

beste Fragen (alle Themen) BestBash - beste Bash-Fragen ** aus

StackOverflow, ServerFault und AskUbuntu ** ClojureFact - Clojure-Fragen aus

Paketüberfluss ** ScalaFact - Scala-Fragen aus

Paketüberfluss ** EclipseFacts - Eclipse-Fragen

von StackOverflow ** jQueryDaily - jQuery Fragen aus

Paketüberfluss ** BestAlgorithms - Algorithmus

Fragen von StackOverflow

Auf jedem dieser Konten werden 2 Tweets pro Tag erstellt, wobei die am höchsten bewerteten Fragen zum jeweiligen Thema angezeigt werden.

6. Fazit

Dieser dritte Artikel schließt die Serie über die Integration in StackOverflow und andere StackExchange-Sites ab, um Fragen über ihre REST-API abzurufen, und die Integration mit Twitter und Spring Social, um diese Fragen zu twittern. Eine potenzielle Richtung, die es wert ist, ausgewertet zu werden, ist dasselbe mit Google Plus - wahrscheinlich Seiten, nicht Konten.

  • 14 Twitter-Konten ** sind als Ergebnis dieses Projekts in Betrieb. Sie konzentrieren sich auf verschiedene Themen und produzieren Inhalte mit geringem Volumen und hoffentlich hoher Qualität (Ideen für andere Tags, die einen eigenen Twitter-Account verdienen, sind in den Kommentaren willkommen).