Автор оригинала: 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) { ListstackSitesForTwitterAccount = 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 вопросы из StackOverflow
- JavaTopSO – Java вопросы из StackOverflow
- RESTDaily – REST вопросы из StackOverflow
- BestJPA – JPA вопросы из StackOverflow
- MavenFact – Maven вопросы из StackOverflow
- BestGit – Git вопросы из StackOverflow
- AskUbuntuBest – AskUbuntu лучшие общие вопросы (все темы)
- ServerFaultBest – ServerFault лучшие вопросы (все темы)
- 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, приветствуются в комментариях).